Rendering HTML inside textarea - javascript

I need to be able to render some HTML tags inside a textarea (namely <strong>, <i>, <u>, <a>) but textareas only interpret their content as text. Is there an easy way of doing it without relying on external libraries/plugins (I'm using jQuery)?
If not, do you know of any jQuery plugin I could use to do this?

This is not possible to do with a textarea. You are looking for a content editable div, which is very easily done:
<div contenteditable="true"></div>
jsFiddle
div.editable {
width: 300px;
height: 200px;
border: 1px solid #ccc;
padding: 5px;
}
strong {
font-weight: bold;
}
<div contenteditable="true">This is the first line.<br>
See, how the text fits here, also if<br>there is a <strong>linebreak</strong> at the end?
<br>It works nicely.
<br>
<br><span style="color: lightgreen">Great</span>.
</div>

With an editable div you can use the method document.execCommand (more details) to easily provide the support for the tags you specified and for some other functionality...
#text {
width: 500px;
min-height: 100px;
border: 2px solid;
}
<div id="text" contenteditable="true"></div>
<button onclick="document.execCommand('bold');">toggle bold</button>
<button onclick="document.execCommand('italic');">toggle italic</button>
<button onclick="document.execCommand('underline');">toggle underline</button>

Since you only said render, yes you can. You could do something along the lines of this:
function render(){
var inp = document.getElementById("box");
var data = `
<svg xmlns="http://www.w3.org/2000/svg" width="${inp.offsetWidth}" height="${inp.offsetHeight}">
<foreignObject width="100%" height="100%">
<div xmlns="http://www.w3.org/1999/xhtml"
style="font-family:monospace;font-style: normal; font-variant: normal; font-size:13.3px;padding:2px;;">
${inp.value} <i style="color:red">cant touch this</i>
</div>
</foreignObject>
</svg>`;
var blob = new Blob( [data], {type:'image/svg+xml'} );
var url=URL.createObjectURL(blob);
inp.style.backgroundImage="url("+URL.createObjectURL(blob)+")";
}
onload=function(){
render();
ro = new ResizeObserver(render);
ro.observe(document.getElementById("box"));
}
#box{
color:transparent;
caret-color: black;
font-style: normal;/*must be same as in the svg for caret to align*/
font-variant: normal;
font-size:13.3px;
padding:2px;
font-family:monospace;
}
<textarea id="box" oninput="render()">you can edit me!</textarea>
This makes it so that a textarea will render html!
Besides the flashing when resizing, inability to directly use classes and having to make sure that the div in the svg has the same format as the textarea for the caret to align correctly, it's works!

Try this example:
function toggleRed() {
var text = $('.editable').text();
$('.editable').html('<p style="color:red">' + text + '</p>');
}
function toggleItalic() {
var text = $('.editable').text();
$('.editable').html("<i>" + text + "</i>");
}
$('.bold').click(function() {
toggleRed();
});
$('.italic').click(function() {
toggleItalic();
});
.editable {
width: 300px;
height: 200px;
border: 1px solid #ccc;
padding: 5px;
resize: both;
overflow: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="editable" contenteditable="true"></div>
<button class="bold">toggle red</button>
<button class="italic">toggle italic</button>

An addendum to this: You can use character entities (such as changing <div> to <div>) and it will render in the textarea.
But when it is saved, the value of the textarea is the text as rendered. So you don't need to de-encode. I just tested this across browsers (Internet Explorer back to version 11).

I have the same problem but in reverse, and the following solution. I want to put html from a div in a textarea (so I can edit some reactions on my website; I want to have the textarea in the same location.)
To put the content of this div in a textarea I use:
var content = $('#msg500').text();
$('#msg500').wrapInner('<textarea>' + content + '</textarea>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="msg500">here some <strong>html</strong> <i>tags</i>.</div>

This is possible with <textarea>.
You only need to use the Summernote WYSIWYG editor.
It interprets HTML tags inside a textarea (namely <strong>, <i>, <u>, and <a>).

Related

Is there a way to have different colored text inside a textarea?

I have an HTML Textarea, which contains a custom-made live editable JSON file where you can see the results of the edits in real-time. I also have something that can cycle through the entries in a "points" attribute, being a list, where it shows the results in the canvas where the JSON results are seen, such that one can see what point is being selected.
I want the point in the textarea to be able to be formatted when selected, such as the selected point in the textarea JSON to be highlighted yellow or have the text color changed to blue or something like that.
I have tried this:
<textarea id="objtext">
not orange
<span style="color:orange">
orange
</span>
not orange
</textarea>
It just showed the textarea having that in it as text, instead of formatting inside the textarea.
How do I make it formatted (and editable and readable by code with textarea.value ideally without the formatting)?
I don't think this is possible with textarea. I think epascarello is trying to tell you that it is possible using a div with the attribute contenteditable="true".
Check out this similar question - Is it possible to have several different textcolors in one textarea?
You will need to style the div to look and feel like a textarea. Here's a basic mockup, you may need to add some Javascript to extend this.
<div id="objtext" contenteditable="true">
not orange
<span class="orange-text">
orange
</span>
not orange
</div>
#objtext {
-moz-appearance: textfield-multiline;
-webkit-appearance: textarea;
border: 1px solid gray;
overflow: auto;
padding: 4px;
width: 400px;
height: 200px;
font: medium -moz-fixed;
font: -webkit-small-control;
}
.orange-text {
color: orange;
}
::selection {
color:orange;
}
::-moz-selection {
color:orange;
}
https://jsfiddle.net/miainchambers/g07rcb5o/2/
Text value can be retrieved by using document.getElementById("objtext").textContent
Unfortunately, it's not possible to do this with a textarea nor input tags.
You can use instead:
contenteditable attribute
<div contenteditable="true">
Lorem Ipsum <span style="color: red;">Lorem</span>
</div>
WYSIWYG editor like https://github.com/tinymce/tinymce
Similar tools depending on the complexity you have to provide
Check out Highlight.js + an editable div.
Example:
<link rel="stylesheet" href="/path/to/styles/default.css">
<link rel="stylesheet"
href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.2.0/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.2.0/highlight.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', (event) => {
document.querySelectorAll('code').forEach((el) => {
hljs.highlightElement(el);
});
});
</script>
<pre><code class="hightlight-json" contenteditable="True">{
"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": "None",
}
}
}
</code>
</pre>

Displaying text in textarea with formatting in place (e.g. <br>)

How can I display a wall of text example:
hello
<br>
how is your day
<br>
123
Into
hello
how is your day
123
I'm trying to display these into a textarea field as well.
I've tried with this
$('<textarea />').html(theString).text(); but it does not display my desired result
Edit:
Current code:
function displayCustom (data) {
var myString= data.getAttribute("data-contentDetails");
$('#textareaContent").html(myString);
}
this is not possible to do this with textarea. you can use content editable div
var theString = `Hello.<br>Hi.<br>Hey, <strong>user</strong> <span style="color: red">Logout</span>.`
// in pure js
document.getElementById('textareaContent').innerHTML = theString;
// OR in jQuery
$('#textareaContent').html(theString)
div {
width: 250px;
height: 150px;
border: 1px solid #ababab;
padding: 8px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="textareaContent" contenteditable="true"></div>
UPDATE
if you have to use textarea and just need to use <br /> (you couldn't use another HTML tag as a text) you can use:
var myString = `Hello<br>Hi<br>Hey, use`
$('#text').html(myString.replace(/<br>/g, '\n'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<textarea id="text"></textarea>
Use a Div with a contenteditable attribute if you want the user to edit the displayed new format. Try to append or insert this.
For a textarea
$('<div contenteditable="true" />').html(theString);
Just remove the contendeditable="true" attribute if you just want to display the new format.

classList.toggle() for multiple divs

I have 3 divs as colors to choose from and 3 blank divs. I want to let the user be able to:
(1) click a colored div and then a blank div, then the blank div is colored as the color the user choose. And the code seems to work.
(2) I want the user to be able to click the colored blank div again and it becomes white. And the code seems to work.
The problem is, if the blank div is colored and the user choose another color and click the colored blank div again, a newer color class will be added to the div, and things become unpredictable. You can open the console and track the messy change of the class of the blank div.
How can I solve this problem? I only want the blank divs to toggle between two classes.
var chosenColor;
function pickColor(arg){
chosenColor=arg.id;
}
function draw(id){
document.getElementById(id).classList.toggle("white");
document.getElementById(id).classList.toggle(chosenColor);
}
.box{
width: 100px;
height: 100px;
border: 1px solid black;
display: inline-block;
}
.red{background: red}
.blue{background: blue;}
.yellow{background: yellow;}
.white{background: white;}
<html>
<body>
<div class="box red" id="red" onclick="pickColor(this)">1</div>
<div class="box blue" id="blue" onclick="pickColor(this)">2</div>
<div class="box yellow" id="yellow" onclick="pickColor(this)">3</div>
<br><br>
<div class="box white" id="4" onclick="draw(4)">4</div>
<div class="box white" id="5" onclick="draw(5)">5</div>
<div class="box white" id="6" onclick="draw(6)">6</div>
</body>
</html>
Instead of using classes and running into the issue of assigning multiple nested classes or having to use complicated white logic...
I'd use data-* attribute:
var chosenColor;
function pick(el) {
chosenColor = el.dataset.color;
}
function draw(el) {
el.dataset.color = el.dataset.color ? "" : chosenColor;
}
body { background: #eee; }
.box {
width: 100px;
height: 100px;
border: 1px solid black;
display: inline-block;
background: white; /* BY DEFAULT !!! */
}
[data-color=red] { background: red; }
[data-color=blue] { background: blue; }
[data-color=yellow] { background: yellow; }
<div class="box" onclick="pick(this)" data-color="red">1</div>
<div class="box" onclick="pick(this)" data-color="blue">2</div>
<div class="box" onclick="pick(this)" data-color="yellow">3</div>
<br><br>
<div class="box" onclick="draw(this)">4</div>
<div class="box" onclick="draw(this)">5</div>
<div class="box" onclick="draw(this)">6</div>
What the ternary el.dataset.color = el.dataset.color ? "" : chosenColor; does is:
if the element has already any data-color set data-color to "" (nothing)
otherwise set data-color to the preselected chosenColor
Check to see if the element's classname is white. If not, set its class name to white - else, set it to the chosen color. You can put the boxes in a container and use .container > div selector, removing the need to give the boxes the .box class. Also, in a listener, this will refer to the clicked element - there's no need to use getElementById when you already have a reference to the element.
var chosenColor;
function pickColor(arg) {
chosenColor = arg.id;
}
function draw(element, id) {
if (element.className !== 'white') element.className = 'white';
else element.className = chosenColor;
}
.container > div {
width: 100px;
height: 100px;
border: 1px solid black;
display: inline-block;
}
.red {
background: red
}
.blue {
background: blue;
}
.yellow {
background: yellow;
}
.white {
background: white;
}
<div class="container">
<div class="red" id="red" onclick="pickColor(this)">1</div>
<div class="blue" id="blue" onclick="pickColor(this)">2</div>
<div class="yellow" id="yellow" onclick="pickColor(this)">3</div>
<br><br>
<div class="white" id="4" onclick="draw(this, 4)">4</div>
<div class="white" id="5" onclick="draw(this, 5)">5</div>
<div class="white" id="6" onclick="draw(this, 6)">6</div>
</div>
Answer
See - https://codepen.io/stephanieschellin/pen/xyYxrj/ (commented code)
or ...
var activeColor
function setPickerColor(event) {
activeColor = event.target.dataset.boxColorIs
}
function setThisBoxColor(event) {
let element = event.target
let the_existing_color_of_this_box = element.dataset.boxColorIs
if (the_existing_color_of_this_box == activeColor) {
delete element.dataset.boxColorIs
} else {
element.dataset.boxColorIs = activeColor
}
}
.box {
width: 100px;
height: 100px;
border: 1px solid black;
display: inline-block;
background: white;
}
[data-box-color-is="red"] {
background: red
}
[data-box-color-is="blue"] {
background: blue;
}
[data-box-color-is="yellow"] {
background: yellow;
}
<html>
<body>
<div id="box-1" class="box" data-box-color-is="red" onclick="setPickerColor(event)">1</div>
<div id="box-2" class="box" data-box-color-is="blue" onclick="setPickerColor(event)">2</div>
<div id="box-3" class="box" data-box-color-is="yellow" onclick="setPickerColor(event)">3</div>
<br>
<br>
<div id="box-4" class="box" onclick="setThisBoxColor(event)">4</div>
<div id="box-5" class="box" onclick="setThisBoxColor(event)">5</div>
<div id="box-6" class="box" onclick="setThisBoxColor(event)">6</div>
</body>
</html>
Using data- attributes you are able to decouple the JavaScript functional concerns form the CSS classes. This simplifies your logic but most importantly it allows folks styling your app to work independently from the folks adding JS functionality. This decoupling becomes really important when your team is using BEM or an OOCSS pattern.
Ideally instead of attaching styles to the data- attribute you would maintain the 'state' using data- and have another function that sets the classList based on the data- state. Allowing you to be 100% sure style changes you make will never effect JS functionality (QA will love you). But that's an evolution beyond this post.
With this setup we are not using the id's but I left them in because its an important best practice. Most likely this code would evolve into a component with listeners instead of inline onClick calls. JavaScript selectors should always be attached to id's or data- variables, never classes. Also, the id's should always be there for the QA team to utilize in their scripts. You risk some one changing a class name or removing it to adjust the styles and inadvertently breaking your JS listener.
I switched the arguments to pass the 'event' instead of the 'this' which is the element. Anyone using your JS event functions is going to expect the event object as the first parameter. You can pass 'this' as the second parameter if you like, but event.target will give you the same thing.
One other thing to note is the syntax change between declaring the data- variable and calling it from the JS.
HTML <div data-box-color-is="red">1</div>
JS event.target.dataset.boxColorIs
Regardless of how you format you data- attribute name it will always be parsed into camelCase when referencing it in JS ... data-box_color--IS would still become ... dataset.boxColorIs
Also as an evolution to your code you could remove the global JS var and store the value on the <body> or some other element on the page using data-. This will give you a single source of truth or 'state' that multiple features/components can reference without cluttering the global space.
Further Reading
https://css-tricks.com/bem-101/
https://en.bem.info/
https://philipwalton.com/articles/side-effects-in-css/
https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/
https://philipwalton.com/articles/decoupling-html-css-and-javascript/

Button highlighting not working inside textarea [duplicate]

I need to be able to render some HTML tags inside a textarea (namely <strong>, <i>, <u>, <a>) but textareas only interpret their content as text. Is there an easy way of doing it without relying on external libraries/plugins (I'm using jQuery)?
If not, do you know of any jQuery plugin I could use to do this?
This is not possible to do with a textarea. You are looking for a content editable div, which is very easily done:
<div contenteditable="true"></div>
jsFiddle
div.editable {
width: 300px;
height: 200px;
border: 1px solid #ccc;
padding: 5px;
}
strong {
font-weight: bold;
}
<div contenteditable="true">This is the first line.<br>
See, how the text fits here, also if<br>there is a <strong>linebreak</strong> at the end?
<br>It works nicely.
<br>
<br><span style="color: lightgreen">Great</span>.
</div>
With an editable div you can use the method document.execCommand (more details) to easily provide the support for the tags you specified and for some other functionality...
#text {
width: 500px;
min-height: 100px;
border: 2px solid;
}
<div id="text" contenteditable="true"></div>
<button onclick="document.execCommand('bold');">toggle bold</button>
<button onclick="document.execCommand('italic');">toggle italic</button>
<button onclick="document.execCommand('underline');">toggle underline</button>
Since you only said render, yes you can. You could do something along the lines of this:
function render(){
var inp = document.getElementById("box");
var data = `
<svg xmlns="http://www.w3.org/2000/svg" width="${inp.offsetWidth}" height="${inp.offsetHeight}">
<foreignObject width="100%" height="100%">
<div xmlns="http://www.w3.org/1999/xhtml"
style="font-family:monospace;font-style: normal; font-variant: normal; font-size:13.3px;padding:2px;;">
${inp.value} <i style="color:red">cant touch this</i>
</div>
</foreignObject>
</svg>`;
var blob = new Blob( [data], {type:'image/svg+xml'} );
var url=URL.createObjectURL(blob);
inp.style.backgroundImage="url("+URL.createObjectURL(blob)+")";
}
onload=function(){
render();
ro = new ResizeObserver(render);
ro.observe(document.getElementById("box"));
}
#box{
color:transparent;
caret-color: black;
font-style: normal;/*must be same as in the svg for caret to align*/
font-variant: normal;
font-size:13.3px;
padding:2px;
font-family:monospace;
}
<textarea id="box" oninput="render()">you can edit me!</textarea>
This makes it so that a textarea will render html!
Besides the flashing when resizing, inability to directly use classes and having to make sure that the div in the svg has the same format as the textarea for the caret to align correctly, it's works!
Try this example:
function toggleRed() {
var text = $('.editable').text();
$('.editable').html('<p style="color:red">' + text + '</p>');
}
function toggleItalic() {
var text = $('.editable').text();
$('.editable').html("<i>" + text + "</i>");
}
$('.bold').click(function() {
toggleRed();
});
$('.italic').click(function() {
toggleItalic();
});
.editable {
width: 300px;
height: 200px;
border: 1px solid #ccc;
padding: 5px;
resize: both;
overflow: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="editable" contenteditable="true"></div>
<button class="bold">toggle red</button>
<button class="italic">toggle italic</button>
An addendum to this: You can use character entities (such as changing <div> to <div>) and it will render in the textarea.
But when it is saved, the value of the textarea is the text as rendered. So you don't need to de-encode. I just tested this across browsers (Internet Explorer back to version 11).
I have the same problem but in reverse, and the following solution. I want to put html from a div in a textarea (so I can edit some reactions on my website; I want to have the textarea in the same location.)
To put the content of this div in a textarea I use:
var content = $('#msg500').text();
$('#msg500').wrapInner('<textarea>' + content + '</textarea>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="msg500">here some <strong>html</strong> <i>tags</i>.</div>
This is possible with <textarea>.
You only need to use the Summernote WYSIWYG editor.
It interprets HTML tags inside a textarea (namely <strong>, <i>, <u>, and <a>).

How to remove "no file selected" from type=file inputs?

I can't seem to figure out any way to remove the "No file selected" text that shows up next to inputs of type "file".
Do you guys know any way how to remove this text?
input[type='file'] {
color: transparent;
}
Enjoy
There is no cross-browser way to do this. The "no file selected" text is in the implementation-defined part of the widget, and I don't believe that most browsers offer much in the way of browser-specific customization. On the other hand, you could simply use CSS to cover the text with something when the value attribute is empty.
You can do this by defining a width to the input and hiding the exceeding content (the undesired "No file selected" text).
input {
width: 132px;
overflow:hidden;
}
Here is the demonstration on jsfiddle.
Beware: each language has its own default text and it may render different input sizes. In brazilian portuguese that 132px width is fine!
My answer was based on this similar question on stackoverflow.
You can replace the file field with a button with the answer to this question: file upload button without input field?
CSS
<style>
#image_file{
position: relative;
width: 188px;
border: 1px solid #BBB;
margin: 1px;
cursor: pointer;
float: left;
}
</style>
HTML
<input id="image_file" onclick="getFile()" onfocus="this.blur()" value=""/>
<div style='height: 0px;width: 0px; overflow:hidden;'>
<input type="file" id="PinSpot_file">
</div>
<input type="button" onclick="getFile()" style="background-color: #DDD;" value="Browser" >
JAVASCRIPT
function getFile(){
document.getElementById("PinSpot_file").click();
}
// Event when change fields
$('#PinSpot_file').live('change', function(e) {
var file = this.value;
var fileName = file.split("\\");
document.getElementById("image_file").value = fileName[fileName.length-1];
//AJAX
}
This is a really good hack and its a lot cleaner.
HTML
<div id="file_info' style='display:inline;'>Browse</div>
<input type="file" name='file[]' multiple style='opacity: 0;' onchange='displayFileName()'/>
JS
function displayFileName() {
var files = $('input[type="file"]')[0].files;
document.getElementById('file_info').innerHTML = files.length + " images to upload";`
}
Well, since there is no way to completely disable the text, I'd suggest either placing an element over the text or try the following solution..
CSS
input[type="file"] {
width: 90px; /* Keep it under 100px in order to hide the unwanted text. */
}
and add an html inline-title attribute to the element to hide the "No File Chosen" hover text.
HTML
<input type="file" id="FileId" title="">
or, you could do it all with JavaScript.
JS
document.addEventListener('DOMContentLoad', myFunction);
function myFunction() {
const FilePicker = document.getElementById('FileId');
FilePicker.style.width = "90px";
FilePicker.title = ""; // Leave This Empty
}
You can try this. Its work for me firefox browser
<style type="">
input[type='file'] {
color: transparent;
}
</style>

Categories

Resources