Input
A standard text input field for forms. Built on the native <input> element with CVA variants for visual style and responsive sizing. Supports all native input types including text, email, password, number, and more.
Anatomy
A single <Input> component wrapping a native input element with data-slot="input". Styled via CVA with two axes: variant (visual style) and size (dimensions). Both produce responsive output across breakpoints.
Variants
Two visual variants control the input's resting appearance.
variant="default"Bordered input with background. Standard choice for most forms.
variant="ghost"Transparent border, hover background. For inline editing or minimal UI.
Responsive Sizes
Three sizes that scale automatically across breakpoints using Tailwind media queries.
size="sm"h-7 / sm:h-8 / lg:h-9Compact forms, table filters, inline controls
size="default"h-8 / sm:h-9 / lg:h-10Standard forms, settings pages
size="lg"h-10 / sm:h-11 / lg:h-12Hero forms, onboarding, search bars
Input Types
The component supports all native HTML input types. The browser provides built-in validation and UI for specialized types.
Text (default)
Password
Number
Search
States
Inputs respond to focus, hover, disabled, and validation states. The focus ring uses focus-visible for keyboard-only display.
Default
Focused
Disabled
Invalid
Valid
With Labels
Always pair inputs with a <Label> connected via htmlFor. This enables click-to-focus and provides an accessible name.
Design Guidelines
Do
- Always pair with a label. Even if visually hidden, every input needs an accessible name via label, aria-label, or aria-labelledby.
- Use the right input type. Email, number, tel, and url types enable mobile keyboards and browser validation.
- Provide helpful placeholders. Show the expected format (e.g., "you@example.com") but never use placeholder as a substitute for a label.
- Show validation inline. Use aria-invalid and pair with a visible error message near the field.
Don't
- Don't use placeholder as a label. Placeholders disappear on input and cannot be relied on for accessibility.
- Don't override responsive sizes inline. Adding manual h-* classes breaks the design token chain.
- Don't disable without explanation. Disabled inputs should have a tooltip or nearby text explaining why.
- Don't rely on color alone for errors. Always pair the red ring with a text error message.
Developer Reference
Accessibility
- Focus ring uses
focus-visible— keyboard-only, not on mouse click. aria-invalidtriggers a destructive ring for validation errors.data-validtriggers a success ring for confirmed-valid fields.disabledsets pointer-events: none and reduced opacity.- File inputs have special styling — the button portion is styled via
file:pseudo-class. - Selection color uses
selection:bg-primary selection:text-primary-foreground.
Usage
import { Input } from "@/components/ui/input"
// Basic
<Input placeholder="Default input" />
<Input type="email" placeholder="Email address" />
<Input type="password" placeholder="Password" />
// Variants
<Input variant="default" placeholder="Default" />
<Input variant="ghost" placeholder="Ghost" />
// Sizes — responsive scaling
<Input size="sm" placeholder="Small" /> {/* h-7 → h-8 → h-9 */}
<Input placeholder="Default" /> {/* h-8 → h-9 → h-10 */}
<Input size="lg" placeholder="Large" /> {/* h-10 → h-11 → h-12 */}
// States
<Input disabled placeholder="Disabled" />
<Input aria-invalid placeholder="Invalid" />
<Input data-valid placeholder="Valid" />
// With label
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" placeholder="you@example.com" />