Good day.
In the development of interfaces, it is sometimes possible to meet the task of highlighting user-entered text depending on certain conditions. (For example, a server grammar check was implemented, or it is necessary to highlight certain words / sections, etc., in a certain color)
However, the textarea element does not support html \ bb tags. As one of the solutions, use contenteditable in div elements.
In this short article, I propose to consider in more or less detail how to select text using textarea.
General idea of the solution
Since there is no way to add tag support to the textarea, the next option is to use "layering."
With the help of z-index and absolute positioning, we place the pre block behind the textarea we need.
In the pre element we set up a font similar to the textarea and also set css properties that will allow us to mirror the text of the textarea block (about them just below)
We will also create a class that, after each change in the content of the textarea, synchronizes data, searches for the data necessary for selection.
Illustration of this solution:

Parse solution
Let's take the main task - creating a class that receives the values of the target node (textarea) as input, functions - checks for the selection and font value (css of the font property)
The class constructor must add a pre element to the DOM document model, position it, and hang events. Here you can add the installation of css properties.
')
/** * "" textarea * @name TextareaExtension * @param target - textarea * @param processor - * @param font - */ function TextareaExtension(target , processor, font) { var setStyleOptions = function() { // ( ), DOM, font preItem.className = "text-area-selection"; target.parentNode.appendChild(preItem); target.style.font = preItem.style.font = font || "14px Ariel"; // , , target.style.width = preItem.style.width = target.offsetWidth + "px"; target.style.height = preItem.style.height = target.offsetHeight + "px"; preItem.style.top = target.offsetTop + "px"; preItem.style.left = target.offsetLeft + "px"; target.style.background = "transparent"; target.style.overflow = "scroll"; // pre margin = 1em 0px. . //( , span pre ) preItem.style.margin = "0px 0px"; } setStyleOptions(); // if (target.addEventListener) { // textarea target.addEventListener("change", this.analyse, false); target.addEventListener("keyup", this.analyse, false); // - textarea pre target.addEventListener("scroll", this.scrollSync, false); // resize target.addEventListener("mousemove", this.resize, false); } else if (target.attachEvent) { target.attachEvent("onchange", this.analyse); target.attachEvent("onkeyup", this.analyse); target.attachEvent("onscroll", this.scrollSync); target.attachEvent("mousemove", this.resize); } }
So, the frame of the class is created. Define the remaining class methods:
this.scrollSync = function () { preItem.scrollTop = target.scrollTop; }; this.resize = function () { preItem.style.width = target.style.width; preItem.style.height = target.style.height; preItem.style.top = target.offsetTop + "px"; preItem.style.left = target.offsetLeft + "px"; }; this.analyse = function (){ var text = target.value; var words = text.split(/[\s]/); var textPosition = 0; var result = ""; for (var i in words) { if (processor(words[i])) { var textIndex; if (text.indexOf) { textIndex = text.indexOf(words[i]); } else textIndex = findText(text, words[i]); result += text.substr(0, textIndex) + "<span class='text-color-bordered text-checker'>" + words[i] + "</span>"; text = text.substr(textIndex + words[i].length, text.length); } } result += text; preItem.innerHTML = result; };
The analyze method iterates through each word, sending it to a function defined in advance. If the word should be highlighted - the method copies the previous content to the pre and “wraps” the necessary word in the span with the class that determines the selection method (in this example, the underscore underscore)
For browsers that do not support the indexOf function, we define the direct search method - findText (in it we implement a direct pass through the arrays)
CSS properties
Here is a list of certain properties, and then analyze them:
.text-area-selection { position:absolute; padding:2px; z-index:-1; display:block; word-wrap:break-word; white-space:pre-wrap; color:white; overflow:scroll; } .text-color-bordered { border-bottom:1px dotted red; }
As already mentioned, the pre element must be positioned under the textarea, so we position it absolutely and set the z-index to -1. Add indents, scrolls.
We now turn to the definitions of word-wrap and white-space. In this task, these properties play a very important role.
white-space: pre-wrap allows you to take into account all the spaces in the lines and at the same time it does not allow you to continue the text horizontally (transfers it) if it does not fit in 1 line
word-wrap: break-word - defines the behavior of the text, in which words that do not fit on 1 line do not stretch an element, but are transferred to another line.
As a result, we get the selection of the text on the result of the work of our function:

Sources:
GitHub linkCodepenExtensions
This example presents the operation method for the built-in function.
In certain situations, there are cases when the result (select / not select) must be obtained from the server. In this case, it is possible to use the pattern command to send only a list of changes to the server. And, directly, the selection is organized in a separate callback function.