Home / Snippets / UI Components /

Textarea

Styled textarea with focus ring, character count hint, and auto-resize — dark-mode ready, pure CSS.

0 / 500 characters
Widely Supported
uino-js

Quick implementation

/* HTML:
<div class="field">
  <label for="msg">Your message</label>
  <textarea class="css-textarea" id="msg" placeholder="Write something…"></textarea>
  <span class="textarea-hint">0 / 500 characters</span>
</div> */

.field {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.field label {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text);
}

.css-textarea {
  width: 100%;
  min-height: 8rem;
  padding: 0.75rem 1rem;
  background: var(--bg);
  border: 1.5px solid oklch(0.35 0.02 260);
  border-radius: 0.5rem;
  color: var(--text);
  font-family: inherit;
  font-size: 0.95rem;
  line-height: 1.6;
  resize: vertical;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
  box-sizing: border-box;
}

.css-textarea::placeholder {
  color: var(--muted);
}

.css-textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px oklch(0.72 0.19 265 / 0.2);
}

.textarea-hint {
  font-size: 0.8rem;
  color: var(--muted);
  text-align: right;
}

@media (prefers-reduced-motion: reduce) {
  .css-textarea {
    transition: none;
  }
}

Prompt this to your LLM

Includes role, constraints, two framework variants, and edge cases to handle.

You are a senior frontend engineer building accessible form components.

Goal: A styled textarea with a visible focus ring, a muted character-count hint below it, and vertical resize support — pure CSS, no JavaScript required for the visual states.

Technical constraints:
- Remove the default outline on focus and replace it with border-color + box-shadow glow using oklch() alpha.
- Use oklch() for all color values, never hex or rgba().
- The border must be 1.5px solid in the resting state and transition to the accent color on :focus.
- The ::placeholder color must use the muted design token.
- Wrap all transitions in @media (prefers-reduced-motion: reduce).
- The component must work correctly in a dark-mode-only design system (prefers-color-scheme: dark).

Framework variant (pick one):
A) Vanilla HTML + CSS — label, textarea, and hint span wrapped in a .field container.
B) React component — accept id, label, placeholder, maxLength, and value/onChange props; render the character count dynamically.

Edge cases to handle:
- Invalid/error state: red border and glow using oklch() red hue.
- Disabled state: reduced opacity, cursor: not-allowed, no focus ring.
- resize: none variant for fixed-height contexts such as chat inputs.
- Very long placeholder text must wrap gracefully inside the textarea bounds.

Return HTML + CSS (or React + CSS).

Why this matters in 2026

Default browser textarea styling is inconsistent across platforms and almost always looks out of place in a custom design system. A well-styled textarea — with a clear focus ring, restrained resize handle, and a muted character hint — signals to users that the interface is polished and accessible. In dark-mode-only designs, the challenge is compounding: default form controls use light-mode system colors that can appear as blinding white boxes against dark backgrounds. Replacing them with oklch()-based border and shadow values keeps everything perceptually consistent.

The logic

The resting border uses a low-lightness oklch() value to remain visible against the dark background without screaming for attention. On :focus, both the border-color and a semi-transparent box-shadow ring update simultaneously, giving users two distinct visual cues about the active field. The transition on both properties is wrapped in a prefers-reduced-motion query so the state change still happens — just instantly — for users who prefer no motion. The resize: vertical property retains browser-native height control while preventing the textarea from breaking horizontal layouts.

Accessibility & performance

The <label> element must be explicitly associated with the textarea via matching for and id attributes — never rely on placeholder text as a label, because it disappears when the user starts typing. The character-count hint should be linked to the textarea with aria-describedby so screen readers announce it alongside the field description. All visual transitions use border-color and box-shadow, both compositor-friendly properties that do not trigger layout recalculation. The resize: vertical constraint is purely cosmetic and does not affect accessibility.