Source Code

<div class="apc-wrap">
  <div class="apc-topbar">
    <select class="apc-model-select" id="apcModel">
      <option value="8000">Swift-1 (fast)</option>
      <option value="32000" selected>Orbit-3 (balanced)</option>
      <option value="128000">Titan-X (advanced)</option>
    </select>
    <div class="apc-token-meta">
      <span id="apcTokenLabel">~0 / 32000 tokens</span>
    </div>
  </div>

  <div class="apc-token-bar-track"><div class="apc-token-bar-fill" id="apcTokenFill"></div></div>

  <div class="apc-composer">
    <textarea id="apcTextarea" class="apc-textarea" placeholder="Ask anything, or describe what you'd like help with..." rows="1"></textarea>
    <div class="apc-toolbar">
      <button class="apc-attach-btn" id="apcAttachBtn" title="Attach a file" type="button">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.44 11.05l-9.19 9.19a5 5 0 0 1-7.07-7.07l9.19-9.19a3.5 3.5 0 0 1 4.95 4.95L10.13 17.02a1.5 1.5 0 0 1-2.12-2.12l8.49-8.49"/></svg>
      </button>
      <button class="apc-send-btn" id="apcSendBtn" type="button" disabled>
        Send
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M22 2L11 13"/><path d="M22 2l-7 20-4-9-9-4 20-7z"/></svg>
      </button>
    </div>
  </div>
</div>

AI Prompt Composer with Token Meter — Free HTML CSS JS Snippet

AI Prompt Composer with Token Meter · Forms · Plain HTML, CSS & JS · Live preview

What's included

Features

Auto-growing textarea that expands with content up to a max height, then scrolls
Live estimated token count using a simple, clearly-labeled ~4-characters-per-token heuristic
Model picker whose selected option changes the token ceiling used by the meter
Color-shifting progress bar and label (indigo → amber → red) as usage approaches the limit
Decorative attachment icon button with a brief press feedback animation
Send button disabled whenever the textarea is empty or only whitespace
Clean focus state on the composer border for clear keyboard-input affordance
Fully self-contained vanilla JS — no tokenizer library or external API calls

About this UI Snippet

AI Prompt Composer with Token Meter — LLM Prompt Input with Live Token Estimate

Screenshot of the AI Prompt Composer with Token Meter snippet rendered live

Prompt composer UIs for LLM products typically need three things visible at once: how much context budget is left, which model is selected (since limits differ by model), and a clear way to send. This snippet builds all three from a single textarea's input event, without any external tokenizer library.

A simple, clearly-labeled token estimate

estimateTokens() uses the common rough heuristic of roughly 4 characters per token — Math.ceil(text.length / 4) — which is not exact but is a reasonable approximation for English text and is explicitly labeled with a "~" prefix in the UI so it always reads as an estimate rather than a precise count.

Auto-growing textarea

autoGrow() resets the textarea's height to auto and then sets it to its scrollHeight (capped at 200px, after which it becomes scrollable), which is the standard technique for a textarea that grows with content without any external autosize library.

A limit that changes with the model picker

The model <select>'s option values are themselves the token limits (8000, 32000, 128000) for each fake model tier. getLimit() just reads and parses the current option's value, so switching models immediately recalculates the percentage and re-renders the meter against the new ceiling — no separate lookup table needed.

A progress bar that changes color near the limit

updateMeter() computes the percentage of the limit used and applies one of three colors to both the label text and the bar fill: indigo under 70%, amber from 70–90%, and red at 90% and above — giving an at-a-glance warning before the user actually exceeds the model's context window.

Step by step

How to Use

  1. 1
    Load the snippetClick "AI Prompt Composer with Token Meter" in the sidebar to load its HTML, CSS, and JS into the editor panels. The preview updates instantly.
  2. 2
    Edit the codeModify any panel — HTML, CSS, or JS. The preview refreshes as you type. Use Reset in each panel header to restore the original.
  3. 3
    Preview on devicesClick the Mobile (375px), Tablet (768px), or Desktop buttons in the preview header to check responsiveness.
  4. 4
    Export in your formatClick "HTML" to download a standalone file, "JSX" for a React component, "Tailwind" for a React + Tailwind CSS component, "Tailwind HTML" for a standalone HTML file with Tailwind CDN, "Vue" for a Vue 3 SFC with <template>/<script setup>/<style scoped>, or "Angular" for a standalone Angular .component.ts file. "Copy all" copies the full code to clipboard.
  5. 5
    Save your versionClick "Save as", type a name, and press Enter. Your snippet saves to IndexedDB and appears in the Saved tab.

Real-world uses

Common Use Cases

AI chat and prompt-based product interfaces
A ready-made composer bar for any LLM-powered chat or completion tool.
Internal AI tooling and playgrounds
Let teams see roughly how much of their context budget a draft prompt uses before sending it.
Multi-model product demos
Show how switching models changes available context length in a tangible, visual way.
Teaching auto-resizing textareas and live input metrics
A compact example combining textarea autosize with a derived, styled progress indicator.

Got questions?

Frequently Asked Questions

No — it uses a simple heuristic (roughly one token per 4 characters) and is explicitly labeled with a "~" prefix as an estimate. Real tokenizers vary by model and split text differently, so treat this as a rough guide, not an exact count.

Each option in the model dropdown has its token limit as its value attribute. getLimit() reads that value, so switching models immediately recalculates the percentage-used and re-colors the bar against the newly selected ceiling.

It is disabled whenever the textarea's trimmed value is empty, and re-enabled as soon as any non-whitespace text is typed, checked on every input event.

Yes — replace the body of estimateTokens() with a call to a real tokenizer (e.g. a client-side BPE tokenizer for your target model) and the rest of the meter, coloring, and limit logic will work unchanged.