Here is a fully implemented example. The strategy is similar to the one outlined by chris' answer. Basically, we use a contenteditable div to allow the user to enter some content. Once the content is over 10 characters, we use a span to style all subsequent characters.
One issue is that changing the HTML of the editable div (which includes appending a span) will cause the cursor to reset to the beginning. To get around this issue, I used code from this answer to set the cursor back to the end.
<input id='test-value' type='hidden'>
<div id='test' style="border:1px solid" contenteditable="true">
<script>
let input = document.querySelector("#test");
input.addEventListener("keypress", function(e) {
if (e.ctrlKey) return;
let value = input.innerText;
if (value.length > 10) {
let firstTen = value.substring(0, 10);
let remainingText = value.substring(10);
// The text may contain HTML, which could lead to an XSS vulnerability.
// To avoid this we create a span and set the span's innerText instead of
// modifying the input's innerHTML directly.
let span = document.createElement("span");
span.style.color = "red";
span.innerText = remainingText;
input.innerText = firstTen;
input.appendChild(span);
input.focus();
setEndOfContenteditable(input);
}
document.querySelector("#test-value").value = input.innerText;
});
// From https://stackoverflow.com/a/3866442/11981207
function setEndOfContenteditable(contentEditableElement)
{
var range,selection;
if(document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+
{
range = document.createRange();//Create a range (a range is a like the selection but invisible)
range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
selection = window.getSelection();//get the selection object (allows you to change selection)
selection.removeAllRanges();//remove any selections already made
selection.addRange(range);//make the range you have just created the visible selection
}
else if(document.selection)//IE 8 and lower
{
range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible)
range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
range.select();//Select the range (make it the visible selection
}
}
</script>
In your comment you mentioned that you cannot modify the HTML directly. As a workaround, you can use JavaScript to convert your input to a hidden input, and insert a contenteditable div after it.
<!-- Your original HTML, untouched -->
<input type="text" maxlength="255">
<script>
let input = document.querySelector("input");
input.type = "hidden";
let editableDiv = document.createElement("div");
editableDiv.contentEditable = true;
editableDiv.style.border = "1px solid black";
input.parentNode.insertBefore(editableDiv, input.nextSibling);
editableDiv.addEventListener("keypress", function(e) {
if (e.ctrlKey) return;
let value = editableDiv.innerText;
if (value.length > 10) {
let firstTen = value.substring(0, 10);
let remainingText = value.substring(10);
// The text may contain HTML, which could lead to an XSS vulnerability.
// To avoid this we create a span and set the span's innerText instead of
// modifying the editableDiv's innerHTML directly.
let span = document.createElement("span");
span.style.color = "red";
span.innerText = remainingText;
editableDiv.innerText = firstTen;
editableDiv.appendChild(span);
editableDiv.focus();
setEndOfContenteditable(editableDiv);
}
input.value = editableDiv.innerText;
});
// From https://stackoverflow.com/a/3866442/11981207
function setEndOfContenteditable(contentEditableElement)
{
var range,selection;
if(document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+
{
range = document.createRange();//Create a range (a range is a like the selection but invisible)
range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
selection = window.getSelection();//get the selection object (allows you to change selection)
selection.removeAllRanges();//remove any selections already made
selection.addRange(range);//make the range you have just created the visible selection
}
else if(document.selection)//IE 8 and lower
{
range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible)
range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
range.select();//Select the range (make it the visible selection
}
}
</script>