LEARNING OBJECTIVES ⌵
- Understand the fundamental operational differences between
maxlength(hard input blocking) andminlength(soft constraint validation). - Inspect the
ValidityStateAPI flags:validity.tooLongandvalidity.tooShort. - Decode the UTF-16 code unit specification trap: why emojis and non-Latin scripts consume multiple length units.
- Build accurate, accessible live character countdown meters using the modern JavaScript
Intl.SegmenterAPI.
📖 The Mental Model & Story (Intuitive Foundation)
Imagine writing a telegram in the early 20th century. The telegraph operator has a rigid rulebook with two conditions:
- Minimum Length Requirement (
minlength): To prevent accidental button taps, no telegram will be sent unless it contains at least 3 words. If you bring a slip with only 1 word, the clerk will not accept it for transmission. However, the clerk does not slap the pen out of your hand when you start writing your first word—you are permitted to write until you finish. - Maximum Length Barrier (
maxlength): The physical paper tape strip has room for exactly 50 characters. The moment you hit character number 50, the tape ends abruptly. You can press the typewriter keys all day long, but no more letters will physically fit onto the tape.
minlength="5": [ A B C ] --> Soft Warning: "Too short to dispatch" (3/5)
maxlength="10": [ A B C D E F G H I J ] [X] --> Hard Wall: Keystrokes blocked! (10/10)
Now add a modern twist: imagine the telegraph counts characters in 16-bit computer bytes rather than human eyes. When you stamp a single family emoji (👨👩👧👦), the telegraph operator calculates 11 separate units, suddenly exhausting nearly a quarter of your entire telegram strip!
Technical Deep Dive & Specifications
maxlength vs minlength Mechanics
| Attribute | Behavior During Active Typing | Behavior on Form Submit | ValidityState Property |
|---|---|---|---|
maxlength="N" |
Hard Blocking: Browser prevents typing or pasting past $N$ code units | Blocks submission if value length $> N$ | validity.tooLong |
minlength="N" |
Non-Blocking: User can freely type 1, 2, or 3 characters | Blocks submission if length $> 0$ and $< N$ | validity.tooShort |
USER TYPES IN INPUT
|
v
Is string length >= maxlength?
/ \
Yes / \ No
/ \
v v
[ BLOCK KEYSTROKE ] [ INSERT CHARACTER ]
|
v
[ USER CLICKS SUBMIT ]
|
+----------------------------+----------------------------+
| |
Is 0 < length < minlength? Is length > maxlength?
/ \ / \
Yes / \ No Yes / \ No
v \ v \
+-------------------+ v +-------------------+ v
| validity.tooShort | [ VALID ] | validity.tooLong | [ VALID ]
| Submission Blocked| | Submission Blocked|
+-------------------+ +-------------------+
[!NOTE]
minlengthdoes not make a field required! If an input withminlength="8"is completely empty (""), it is considered valid and can be submitted. To require entry, pair it with therequiredattribute.
The Unicode & UTF-16 Code Unit Trap
One of the most treacherous traps in web development stems from how the WHATWG HTML and ECMAScript specifications define string length.
Length is measured in UTF-16 Code Units (16-bit chunks), NOT human-perceived visual characters (Grapheme Clusters).
+---------------------------------------------------------------------------------------+
| UNICODE ENCODING COMPARISON |
+---------------------------------------------------------------------------------------+
| Character | Code Points | UTF-16 Code Units | Grapheme Count |
+-------------------------+----------------------+-------------------+------------------+
| Latin "A" | U+0041 | 1 code unit | 1 character |
| Rocket Emoji "🚀" | U+1F680 | 2 code units | 1 character |
| Family Emoji "👨👩👧👦" | U+1F468 U+200D ... | 11 code units | 1 character |
| Flag "🇺🇸" | U+1F1FA U+1F1F8 | 4 code units | 1 character |
+-------------------------+----------------------+-------------------+------------------+
// The String Length Illusion in JavaScript & HTML:
const text1 = "A";
console.log(text1.length); // 1
const text2 = "🚀";
console.log(text2.length); // 2 (Surrogate pair: \uD83D\uDE80)
const text3 = "👨👩👧👦";
console.log(text3.length); // 11 (Composed with Zero-Width Joiners!)
If an input has maxlength="10", a user attempting to type "Hello 👨👩👧👦" will find their input truncated or blocked because that string consumes 17 UTF-16 code units, even though to human eyes it is only 7 characters long!
Modern Solution: Intl.Segmenter
To calculate true human-perceived character counts in client-side character counters, use the modern JavaScript standard Intl.Segmenter:
function getTrueGraphemeCount(str) {
const segmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });
return Array.from(segmenter.segment(str)).length;
}
console.log(getTrueGraphemeCount("👨👩👧👦")); // 1 (Accurate!)
💻 Interactive Code Playground
Starter Code
Line-by-Line Code Breakdown
- Line 37–43 (
<input type="text" minlength="4" maxlength="15" required>): Combines minimum length, maximum length, and required constraints. - Line 46 (
aria-live="polite"): Informs screen readers of character counter updates politely without aggressively interrupting screen reader speech. - Line 17 (
input:user-invalid): Applies error styling only after the user interacts with the input and violates the 4-character minimum upon blur or submission. - Line 60–63 (
Intl.Segmenter): Compares raw string UTF-16 code units (which govern the browser'smaxlengthcutoff) against true visual graphemes.
Expected Browser Render Output
Character Constraint Lab
Screen Handle (Min 4, Max 15 chars)
[ quantum_🚀 ]
Must be 4–15 characters 10 / 15
Raw Value: "quantum_🚀"
UTF-16 Code Units (HTML Limit): 10 / 15
True Human Graphemes (Intl): 9
validity.tooShort: false
validity.tooLong: false
validity.valid: true🏋️ Hands-On Exercise
🎯 The Challenge: Build a Microblog Status Composer with Visual Progress
Instructions:
- Create a text field for a status update with
minlength="10"andmaxlength="60". - Provide a character counter displaying
"X / 60 characters remaining". - If the user has typed fewer than 10 characters, display a warning message: "At least 10 characters required".
- When remaining characters drop below 10, highlight the counter in bold orange.
- When remaining characters reach 0, highlight the counter in bold red.
- Verify that
validity.tooShortprevents native submission when fewer than 10 characters are entered.
🏁 Starter Code Sandbox
⚠️ Common Pitfalls
- Expecting
minlengthto Block Typing: Unlikemaxlength,minlengthwill never stop a user from typing 1 or 2 characters. It only blocks form submission. - Assuming
minlengthMakes a Field Required: An empty string ("") satisfiesminlength. If you want to force entry, you must explicitly add therequiredattribute. - Database Truncation Crashes Due to Unicode: Setting
maxlength="20"in HTML andVARCHAR(20)in a SQL database will crash or truncate text if the user types 10 complex emojis. Always size backend UTF-8 byte limits (VARCHAR/TEXT) conservatively to account for multi-byte Unicode sequences.
💡 Pro Tips
- Pasting Truncation Awareness: When a user pastes 200 characters into an input with
maxlength="50", the browser silently truncates the pasted text to the first 50 code units without notifying the user. Consider adding anonpastehandler to alert users if their clipboard content was clipped. - Accessible Live Regions for Counters: Add
aria-live="polite"to character counter spans so screen reader users receive auditory updates when approaching character limits without focus interruption.
📌 Key Takeaways
maxlengthprovides hard browser-level input blocking and triggersvalidity.tooLong.minlengthis a soft validation constraint evaluated at submission time, triggeringvalidity.tooShort.- Both attributes measure string length in UTF-16 code units, meaning emojis and surrogate pairs count as 2+ units each.
- Use JavaScript's
Intl.Segmenterto calculate true human-perceived visual grapheme counts. - An empty field passes
minlengthvalidation unless therequiredattribute is also applied. - --