A good first building block

Textarea character counter

Count Unicode code points as you type, with a clear remaining allowance.

HTMLCSSJavaScriptNo dependencies
Edit in playground

Live preview

Explore the result below

HTML

<main><h1>Make every character count</h1><label for="message">Message</label><textarea id="message" rows="5" aria-describedby="counter-note"></textarea><p id="counter-note">This example allows 120 Unicode code points. A composed emoji can use several code points.</p><p><output id="character-count" for="message">0 used · 120 remaining</output></p><button id="clear-message">Clear message</button><p id="counter-status" role="status"></p></main>
Read the complete HTML document
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<title>My code example</title>
<style>
:root{font-family:system-ui,sans-serif;color:#18223b}*{box-sizing:border-box}body{margin:0;min-height:100vh;padding:24px;background:#edf1ff;display:grid;place-items:center}main{width:min(100%,480px);background:white;border-radius:20px;padding:24px}h1{font-size:24px;margin:0 0 16px}button,input,select,textarea{font:inherit}button{min-height:44px;border:1px solid #afbddd;border-radius:10px;padding:10px 14px;background:#eff3ff;color:#18223b;cursor:pointer}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible{outline:3px solid #3658bf;outline-offset:3px}p{line-height:1.65}label{display:block;margin:16px 0 6px}input:not([type=checkbox]),select,textarea{max-width:100%;width:100%;padding:10px;border:1px solid #afbddd;border-radius:8px}button:disabled{opacity:.5;cursor:default}
</style>
</head>
<body>
<main><h1>Make every character count</h1><label for="message">Message</label><textarea id="message" rows="5" aria-describedby="counter-note"></textarea><p id="counter-note">This example allows 120 Unicode code points. A composed emoji can use several code points.</p><p><output id="character-count" for="message">0 used · 120 remaining</output></p><button id="clear-message">Clear message</button><p id="counter-status" role="status"></p></main>
<script>
const input=document.querySelector("#message"),output=document.querySelector("#character-count"),status=document.querySelector("#counter-status"),limit=120;
function update(){const points=Array.from(input.value);if(points.length>limit){input.value=points.slice(0,limit).join("");status.textContent="The message was limited to 120 Unicode code points.";}else status.textContent="";const used=Array.from(input.value).length;output.textContent=used+" used · "+(limit-used)+" remaining";}
input.addEventListener("input",event=>{if(!event.isComposing)update();});input.addEventListener("compositionend",update);document.querySelector("#clear-message").addEventListener("click",()=>{input.value="";update();input.focus();});
</script>
</body>
</html>

A little guide to making it yours

  1. Copy the code and save it in a file named example.html.
  2. Open the file in your browser to see the complete example.
  3. Change the text and structure in the HTML.
  4. Adjust the colors and spacing in the CSS, or experiment in the playground.

How it works

Array.from counts Unicode code points, keeping surrogate pairs together. It does not count user-perceived grapheme clusters: combined emoji and accents can contain several code points. The example waits for input-method composition to finish before enforcing its limit. A real server must apply its own validation; this local demo submits nothing.

Historical purpose: Historical title/link recorded at this exact path. The archived implementation was not recovered; this is newly authored code for the named purpose.

Troubleshooting and limits

The counter counts Unicode code points, so some combined emoji and accented graphemes can count as more than one. Its limit is a local interface rule; enforce any real server limit separately. Keep the label, status and clear action.

This is newly authored code. It uses system fonts and no external assets.

Keep the ideas going