Skip to content

Input

<Input> is a styled <input>. Use it for every single-line value: text, email, URL, search, number. Multi-line is Textarea.

import from "@na/ui/components/input" ▶ Open in Storybook packages/ui/src/components/input.tsx

When to use

  • Any single-line form field.
  • Search bars (paired with a leading icon — see below).

Don’t use Input for: passwords (use PasswordInput), masked formats like phone numbers (the MaskedInput primitive on the roadmap), or rich content.

Default

<Label htmlFor="name">Name</Label>
<Input id="name" placeholder="Acme Corp" />

Types

<Input type> mirrors the native attribute. The browser and assistive tech treat each type differently — pick the right one.

<Input type="email" />
<Input type="url" />
<Input type="number" />
<Input type="search" />

Disabled and read-only

<Input disabled defaultValue="Disabled" />
<Input readOnly defaultValue="Read-only" />

Invalid

<Input aria-invalid={Boolean(fieldState.error)} {...field} />

API

Prop Type Default Description
type "text" | "email" | "url" | "number" | "search" | "tel" | "date" | … "text" Native HTML input type.
disabled boolean false Native disabled. Pointer events suppressed; opacity 50%.
readOnly boolean false Value is selectable but not editable.
aria-invalid boolean false Triggers the destructive ring.
...rest InputHTMLAttributes All native input attributes — placeholder, value, onChange, defaultValue, name, id, …

Design guidelines

✓ Do

  • Pair every Input with a <Label>. Labels carry the field name for screen readers.
  • Use the right `type` — type="email" gets the email keyboard on mobile and validation hints.
  • Set placeholder = an example value, not an instruction. "alice@acme.com" not "Enter your email".

✗ Don't

  • Hide the label visually unless absolutely necessary. Even then, keep it as aria-label.
  • Use Input for passwords. PasswordInput exists for the reveal toggle and browser-toggle hiding.
  • Set fixed widths in px. Inputs grow with the form column; the design system handles spacing.

Accessibility

  • Native <input> semantics. Pair with <Label htmlFor> or aria-labelledby.
  • For invalid state, set aria-invalid and render a FormError with aria-describedby linking it.
  • For type="search", the browser provides a clear-button on most platforms; the design system doesn’t override it.
  • Label — Required pairing for accessible forms.
  • Textarea — Multi-line.
  • PasswordInput — With reveal toggle.
  • Form — react-hook-form integration with built-in error rendering.

▶ Open Input stories in Storybook