Components / Forms

Input

Input is a single-line text control. Inside a Field it claims the field id and the aria-describedby list automatically; outside one, it is a styled <input> you wire yourself.

Loading playground…
Updated 3 days agoEdit on GitHubWeb & native

What it is

A bordered <input> that forwards its ref. Inside a Field, Input reads the context and applies the field id, the aria-describedby token list, and — when the field is invalid or disabled — the matching attributes. The invalid and disabled props let a standalone Input set the same state without a Field.

Input accepts every standard <input> attribute except size (which collides with the style system). Pass type, placeholder, value, onChange, and the rest as usual.

Install

Input is exported from usemotif. No separate install.

example.tsx
import { Input } from 'usemotif';

API

Input

stable
const Input: ForwardRefExoticComponent<InputProps & RefAttributes<HTMLInputElement>>
invalidboolean

Marks the input invalid — a red border and `aria-invalid`. Falls back to the Field context value when omitted.

typestring= "text"

The HTML input type. `text`, `email`, `search`, `url`, and the rest.

styleCSSProperties

Inline style merged on top of the bordered-surface defaults.

…InputHTMLAttributesOmit<InputHTMLAttributes, "size">

Every standard input attribute except `size`. `placeholder`, `value`, `onChange`, `disabled`, and the rest pass through.

Accessibility

Inside a Field, Input is the component the id graph converges on — it claims the field id (so the Label's htmlFor resolves), names its help and error text through aria-describedby, and mirrors the field's invalid and required state into aria-invalid and aria-required. None of that happens standalone; outside a Field, wire id and aria-describedby yourself.

invalid is a styling and ARIA signal, not validation. It draws the red border and sets the attribute — running the validation and deciding when the field is invalid stays with your form logic.

Examples

Inside a Field:

example.tsx
<Field>
<Label>Email</Label>
<Input type="email" placeholder="you@example.com" />
</Field>

Controlled standalone input:

example.tsx
<Input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search"
/>

With a forwarded ref:

example.tsx
const ref = useRef<HTMLInputElement>(null);
 
<Input ref={ref} />;