v0.5

Input

Single-line text field for capturing short user input such as names, emails, numbers, and queries.

Description

Input renders a native <input> wrapped in a styled shell. From the consumer's perspective it is a single-element component (<Input /> does the right thing on its own), but it also exports InputShell and InputProvider for advanced composition. When nested inside a Field, it inherits size, invalid, disabled, and loading automatically through context, so you rarely set those props directly.

Reach for it whenever a form needs a short, single-line text value: emails, names, search queries, currency amounts, phone numbers, file pickers, and the typical settings-pane controls. Pair it with FieldLabel for accessible labelling and with FieldDescription / FieldError for helper and validation copy; the whole stack sits naturally inside a FieldGroup.

Don't use Input for multi-line text; reach for Textarea. For option pickers use Select or NativeSelect. For binary toggles use Checkbox or Switch. For free-form numeric scrubbers (steppers, sliders) reach for the dedicated numeric components instead of type="number".

Installation

pnpm dlx @create-ui/cli add input

Usage

import { Input } from "@/components/ui/input"
<Input type="email" placeholder="Email" />

Examples

Sizes

Three sizes (xs, sm, md) match the surrounding type scale and resize the shell radius. sm is the default. When Input sits inside a Field, the Field’s size is authoritative and cascades through context; set size on the Input only for standalone use.

States

Field propagates invalid, disabled, and loading to the wrapped Input. invalid swaps the border and outline to the error tones, disabled mutes the field, and loading paints the info-tinted outline plus aria-busy on the shell.

With Label

The canonical labelled-input pattern. Wrap the Input in a Field and pair it with a FieldLabel; Field's context drives the label's size, disabled, and invalid styling.

With Description

Add a FieldDescription for inline helper copy: usage hints, format examples, privacy notes. The description tracks Field's invalid and disabled states automatically.

Choose a unique username for your account.

With Error

Set invalid on the Field and render a FieldError with an errors array; the input switches to the error border and the message renders with role="alert". Duplicate messages are de-duplicated automatically.

Composition

Drop Input next to a Button or Select inside a horizontal flex row to build search bars and currency pickers. Set flex-1 on the Input so it fills the remaining space.

Accessibility

Input renders a native <input>, so the browser's text-field semantics, focus order, and IME / autofill behavior come for free. Wrap it in a Field + FieldLabel to give it an accessible name; the label's htmlFor ties to the input's id.

KeyDescription
TabMoves focus to the input.
Shift + TabMoves focus to the previous focusable element.
EnterSubmits the surrounding <form> when present.

ARIA notes:

  • The component does not set an explicit role; the implicit textbox role from <input> is what assistive tech announces.
  • aria-invalid is set on the input automatically when Field invalid (or an explicit aria-invalid prop) is in effect; pair it with a FieldError so the message is announced.
  • InputShell sets aria-busy when loading is true; the shell also becomes non-interactive via pointer-events-none.
  • disabled removes the input from the tab order and disables pointer events.
  • The accessible name must come from a FieldLabel, an aria-label, or an aria-labelledby reference; never rely on the placeholder alone.

Styling

Tailwind override: pass className to merge Tailwind classes with the component's CVA classes (via cn()):

<Input className="font-mono tracking-wide" />

Data slots and attributes: the component sets these for CSS targeting:

  • data-slot="input-shell" on the wrapper div, with data-size="<size>" and the boolean attributes data-invalid, data-disabled, data-loading (each present only when true).
  • data-slot="input" on the inner <input> element, with data-size="<size>".

Target a specific state in CSS:

[data-slot="input-shell"][data-invalid] {
  /* … */
}
  • Field: wraps Input to provide size, invalid, disabled, and loading via context, plus accessible label, description, and error wiring.
  • Textarea: multi-line equivalent; reach for it when the value can span more than one line.
  • NativeSelect: sibling primitive for native option pickers; composes with Input inside a shared row.
  • Select: Radix-based select for richer pickers when the native dropdown isn't enough.

API Reference

Input

Single-line text field. Extends React.ComponentProps<"input"> with size re-typed to the component's size scale, so any standard input attribute (id, name, placeholder, type, value, defaultValue, onChange, onBlur, aria-*, etc.) is accepted. When rendered outside an existing InputProvider, it wraps itself in an InputProvider + InputShell automatically.

Props

PropTypeDefaultDescription
typestring"text"Native <input> type. Common values: email, password, tel, url, search, number, date, time, file.
disabledbooleanfalseDisables the input. Inherited from Field when omitted.
aria-invalidboolean-Marks the input as invalid. Inherited from Field invalid when omitted.
classNamestring-Tailwind classes merged with the component's CVA classes via cn().

Variants

VariantOptionsDefaultDescription
size"xs" "sm" "md""sm"Size scale; controls height, padding, text size, and shell radius. Inherited from Field when omitted.

InputShell

Visual shell around Input. Used automatically when Input is rendered standalone; render it explicitly only when composing icons, slot buttons, or other affordances inside the same border. Extends React.ComponentProps<"div">, so any standard div attribute is accepted. (advanced)

Props

PropTypeDefaultDescription
classNamestring-Tailwind classes merged with the component's CVA classes via cn().
childrenReact.ReactNode-Shell contents, typically an Input plus optional icon slots.

InputProvider

Context provider that broadcasts size, invalid, disabled, and loading down to nested Input and InputShell instances. Most apps inherit these from Field and never render InputProvider directly. (advanced)

Props

PropTypeDefaultDescription
size"xs" | "sm" | "md""sm"Size broadcast to nested Input / InputShell.
invalidbooleanfalseMarks nested inputs as invalid.
disabledbooleanfalseDisables nested inputs.
loadingbooleanfalsePaints the info-tinted loading state on the shell.
childrenReact.ReactNode-Provider subtree.