Published: Mar 20, 2025
When you want to allow the user to enter plaintext information, your first instinct might be to reach for a <textarea>. This works for many cases and requires no special effort to make it work with forms, but also has limitations.
One example is growing the <textarea> dynamically with the content without resolving to hacks. There's field-sizing: content, but it has limited browser support. This is where the contenteditable="plaintext-only" attribute value combination comes in. You can add it to generic elements like <div>, and have the element automatically take care of resizing.
Another limitation is styling. The CSS Custom Highlight API provides a mechanism for styling arbitrary text ranges on a document by using JavaScript to create the ranges, and CSS to style them. A <textarea> internally uses a <div> in the user agent shadow root, which is why styling the text with the CSS Custom Highlight API doesn't work. If used on an element like a <div> directly that you have made contenteditable, the CSS Custom Highlight API works just fine.
<style>
::highlight(highlight) {
background-color: yellow;
color: black;
}
</style>
<div contenteditable="plaintext-only">Edit me</div>
<script>
const parentNode = document.querySelector('div').firstChild;
const range = new Range();
range.setStart(parentNode, 0);
range.setEnd(parentNode, 3);
const highlight = new Highlight(range);
CSS.highlights.set('highlight', highlight);
</script>

Here's a screenshot of the demo that shows this limitation. Note how the text in the <textarea> isn't styled, but the text in the two contenteditable generic <div> elements is.
