Rime

TextInput

The text field: a white box with a tinted edge, a brand halo on focus, adornments and a password reveal.

TextInput is the one box every text-like field wears: Textarea, Select's field trigger, DateField, SearchField and PrefixedInput all share its --input-* tokens, so one theme change moves them together.

Focus is drawn on the whole box, adornments included (a leading icon, a trailing unit, the reveal button), never on the bare <input>. Invalid warms the fill and turns the edge to the danger hue; read-only is a dashed sunken box; disabled is flat and sunken.

It is a plain controlled or uncontrolled <input>: every native attribute passes through (type, autoComplete, inputMode, maxLength).

Installation

npx shadcn@latest add KezLahd/rime/field

Also installs: base, icon.

Usage

import { Field, TextInput } from "@/components/ui";

<Field label="Email" hint="We send the sign-in link here.">
  <TextInput type="email" autoComplete="email" value={email} onChange={(e) => setEmail(e.target.value)} />
</Field>

Examples

In a Field

Label, hint and error come from Field; the input reads them from context.

Shown to everyone on the team.

Adornments and reveal

kg

States

Enter a 4-digit postcode.

API

Generated from the component's TypeScript types and JSDoc (scripts/gen-ui-registry.mjs), so it always matches the source.

TextInput

TextInput props
PropTypeDefaultDescription
leadingIconReactNode
trailingReactNodeRight-hand slot inside the box: a unit ("%"), a clear button.
monobooleanMonospace with slight tracking, for ID numbers, references, postcodes.
invalidbooleanOverrides the Field's invalid state.
revealablebooleanAdds a show/hide toggle. Only meaningful with type="password".
defaultRevealedbooleanfalseStarts with the password readable. For the styleguide and review screens.
size"sm" | "md""md"
boxClassNamestringClass for the outer box rather than the <input>.

Also accepts the native attributes of AriaAttributes, DOMAttributes, HTMLAttributes, InputHTMLAttributes.

Field

Field props
PropTypeDefaultDescription
labelRequiredReactNode
hintReactNode
errorReactNodePresence marks the control invalid. Say what to do, not just what is wrong.
requiredbooleanfalse
optionalbooleanShows "(optional)". Use on forms where most fields are required.
idstringPass to link a field to an ErrorSummary entry. Generated otherwise.
groupbooleanfieldset + legend, for RadioGroup, a checkbox list, OtpInput, DateField.
labelStyle"sentence" | "caps""sentence"sentence = 13px bold (default, reads well for long labels). caps = the reference 11.5px uppercase micro-label, for short auth/admin forms.
labelActionReactNodeSomething on the label's right edge, e.g. a "Forgot password?" link.
hideLabelboolean
classNamestring
childrenRequiredReactNode

Theme tokens

Per-component tokens are undeclared by default, so the default shown is the fallback the CSS uses. Set one at :root (or in theme.css) to restyle every instance. Live values are read from this page, so they follow the Rime Studio.

TextInput per-component tokens
TokenDefaultLive value
--field-focus-borderrgba(var(--rgb-brand), 0.7) / var(--focus-color)…
--field-focus-ringvar(--focus-halo)…
--field-focus-ring-invalid0 0 0 4px rgba(var(--rgb-danger), 0.14)…
--field-hover-borderrgba(var(--rgb-brand-deep), 0.3)…
--input-bgvar(--surface-solid)…
--input-bordervar(--line-input)…
--input-border-widthvar(--border-w-field)…
--input-font-sizevar(--text-input)…
--input-height-mdvar(--field-h-md)…
--input-height-smvar(--field-h-sm)…
--input-pad-xcalc(14px * var(--density))…
--input-radiusvar(--r-md) / var(--r-sm)…
--input-shadowvar(--shadow-input)…

System tokens it reads

TextInput system tokens
TokenDefaultLive value
--border-w-fieldtokens.css…
--danger-basetokens.css…
--danger-field-filltokens.css…
--danger-inktokens.css…
--densitytokens.css…
--durtokens.css…
--easetokens.css…
--field-h-mdtokens.css…
--field-h-smtokens.css…
--focus-colortokens.css…
--focus-halotokens.css…
--font-bodytokens.css…
--font-monotokens.css…
--ink-bodytokens.css…
--ink-brandtokens.css…
--ink-disabledtokens.css…
--ink-mutedtokens.css…
--ink-placeholdertokens.css…
--ink-secondarytokens.css…
--line-inputtokens.css…
--r-mdtokens.css…
--r-smtokens.css…
--r-xstokens.css…
--rgb-brandtokens.css…
--rgb-brand-deeptokens.css…
--rgb-dangertokens.css…
--shadow-inputtokens.css…
--surface-solidtokens.css…
--surface-sunkentokens.css…
--text-bodytokens.css…
--text-captiontokens.css…
--text-inputtokens.css…
--text-smalltokens.css…
--wash-subtletokens.css…

Accessibility

  • Wrap it in <Field label=…>: Field wires the label, hint and error to the control (id, aria-describedby, aria-invalid) through context, so the control needs no ids of its own.
  • Placeholder ink holds 4.97:1 on the white box; never put instructions only in a placeholder.
  • revealable adds a real button inside the box whose name switches between "Show password" and "Hide password" (no aria-pressed, which would read as "Hide password, pressed").
  • Set autoComplete on every personal-data field (WCAG 1.3.5).

Do and don't

Do

  • Size the box to the content where the content is short (a postcode), with a className width.

Don't

  • Don't style the <input> itself; theme the box with --input-* tokens.
  • Don't show an error before the user has left the field or submitted.

For AI agents

This page as markdown, rendered from the same registry entry. Point an agent at it (or add .md to this page's URL), or at /llms.txt for the index.

Open text-input.md

Related: select, textarea, search-field