Fields
Character Count
A live, field-linked count of how much text remains before a native length limit.
When to use it: Use it when a text limit is important enough that people need to plan what they write.
Example
import { CharacterCount, Label, TextArea, TextField } from "@comp0/react";
export function Example() {
return (
<TextField defaultValue="" className="block w-full max-w-md text-base sm:text-sm">
<Label className="mb-1 block font-medium text-zinc-950 dark:text-white">
Short biography
</Label>
<TextArea
name="biography"
maxLength={160}
rows={5}
className="w-full rounded-lg border border-zinc-950/15 bg-white px-3 py-2 outline-teal-600 focus-visible:outline-2 dark:border-white/15 dark:bg-zinc-900 dark:outline-teal-400"
/>
<CharacterCount
maxLength={160}
className="mt-1 block text-zinc-600 data-limit-reached:font-semibold data-limit-reached:text-amber-700 dark:text-zinc-400 dark:data-limit-reached:text-amber-300"
/>
</TextField>
);
}Anatomy
Dashed frames are invisible state providers; shaded shapes own real DOM. Numbered pins match the list below.
A wireframe sketch of the assembled component. Each numbered marker matches a part in the list that follows.
TextField
Wrapper-free value provider shared by the native control and count. Does not add a DOM element.
Label
Visible name for the text control. Owns a DOM element.
TextArea
Native text control that enforces maxLength. Owns a DOM element.
CharacterCount
Polite output associated with the field through aria-describedby and for. Owns a DOM element.
Step by step
- 1
Add the main part
Give TextField an initial or controlled value so it can share the current text with CharacterCount.
- 2
Add the supporting parts
Put the same maxLength on TextArea and CharacterCount; the native control enforces the limit.
- 3
Make the behavior clear
Keep the output visible and concise; it is automatically associated with the field and announced politely.
Exampletsx <TextField defaultValue=""> <TextArea maxLength={160} /> <CharacterCount maxLength={160} /> </TextField>;
Keyboard
- ⇥
- Moves to and from the native text control.
Forms and accessibility
TextArea submits its native value; CharacterCount submits nothing.
Accessibility checklist
- Put the same non-negative maxLength on the native control and CharacterCount so the message matches the enforced limit.
- Keep the count visible and associated with the control; do not communicate the limit only after it is reached.
- Give TextField value, defaultValue, or onChange so CharacterCount receives the current text.
API reference
import { CharacterCount, Label, TextArea, TextField } from "@comp0/react";TextField
Context onlyWrapper-free value provider shared by the native control and count.
| Prop | Type | Description |
|---|---|---|
value | string | Controlled text value. |
defaultValue | string | Initial uncontrolled text value. |
onChange | (value: string) => void | Receives the next text value. |
Label
DOM elementVisible name for the text control.
TextArea
DOM elementNative text control that enforces maxLength.
| Prop | Type | Description |
|---|---|---|
maxLength | number | Native maximum accepted character count. |
CharacterCount
DOM elementPolite output associated with the field through aria-describedby and for.
| Prop | Type | Description |
|---|---|---|
maxLength | number | Non-negative integer used to calculate remaining text. |
children | ReactNode | (state: CharacterCountState) => ReactNode | Custom output receiving count, maximum, remaining, and limitReached. |
Style hooks
Attributes that appear while a state is true. Target them with Tailwind data variants such as data-open:bg-zinc-100, or with any CSS selector.
CharacterCount
| Style hook | Meaning |
|---|---|
[data-empty] | The field has no text. |
[data-limit-reached] | No characters remain. |
[data-count] | Current character count. |
[data-remaining] | Characters remaining before the limit. |