Responsive profile card
A friendly introduction with a flexible layout and a clear next step.
View exampleA good first building block
Count Unicode code points as you type, with a clear remaining allowance.
<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>: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}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();});<!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>example.html.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.
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