Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Limit html text input to a particular number of bytes?

Using HTML5 (or less preferably JavaScript) is it possible to limit the maximum length of an input to a particular number of bytes?

I realise that I can limit to a number of characters with:

<input type="text" maxlength="4" />

But that's not good enough because I can input up to four two-byte chars in it.

Obviously I am validating this server-side, but I would like this on the browser-side too.

Edit: Just to be clear, I do wish to be able to support UTF-8. Sorry @elclanrs.

like image 859
meshy Avatar asked Sep 01 '25 02:09

meshy


2 Answers

this script has a couple minor UX glitches that can be cleaned up, but it does accomplish the basic task outlined when i tested it in chrome:

<input id=myinp />


<script> // bind handlers to input:
   myinp.onkeypress=myinp.onblur=myinp.onpaste= function vld(e){
     var inp=e.target;
     // count bytes used in text:
     if( encodeURIComponent(inp.value).replace(/%[A-F\d]{2,6}/g, 'U').length > 4){
        // if too many bytes, try to reject:
        e.preventDefault;
        inp.value=inp.val||inp.value;
        return false;
     }
     // backup last known good value:
    inp.val=inp.value;
   }

</script>
like image 86
dandavis Avatar answered Sep 02 '25 15:09

dandavis


Throughout my own findings, I figured this works really well:

function limit_input(n) { // n = number of bytes
  return function(e) {
    const is_clipboard = e instanceof ClipboardEvent;
    if(is_clipboard && e.type != "paste") {
      return;
    }
    let new_val = e.target.value;
    if(is_clipboard) {
      new_val += e.clipboardData.getData("text");
    } else {
      new_val += e.key;
    }
    if(new TextEncoder().encode(new_val).byteLength -
       e.target.selectionEnd + e.target.selectionStart > n) {
      if(e.target.value == "" && is_clipboard) {
        const old = e.target.placeholder;
        e.target.placeholder = "Text too long to paste!";
        setTimeout(function() {
          e.target.placeholder = old;
        }, 1000);
      }
      e.preventDefault();
    }
  };
}

let el = document.getElementById("your_input");

el.onkeypress = el.onpaste = limit_input(4);

I started out with dandavis' answer and kept on improving it to adapt to all situations. I still don't think this is perfect, and it's still using the deprecated onkeypress handler, but nothing else worked better than this.

You can delete the part of the code that changes placeholder to say the text is too long to paste (delete the whole if, keep only e.preventDefault() in). It's just something I added myself to notify the user why the input is still empty after they try pasting something in. That way they won't blame me for writing faulty code and I won't have to answer a horde of complaints.