Input
StableA single-line text field for names, emails, numbers and search — always paired with a visible label.
We’ll send the invite here.
Installation
$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/input.jsonUsage
import { Field, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"<Field>
<FieldLabel htmlFor="email">Email</FieldLabel>
<Input id="email" type="email" placeholder="you@company.com" />
</Field>An input on its own has no visible name. In forms, always compose it with Field, which lays out the label, description and error message consistently.
Examples
Sizes
sm, default and lg share their heights with Button and Select — 32, 36 and 40px — so an input and its action always align on one row.
Types
prfct styles every native input type. Choose the right type and inputMode so mobile keyboards match the data, and set autoComplete so browsers and password managers can fill the field.
Invalid
Set aria-invalid on the input and data-invalid on its Field, and explain the problem with a FieldError linked through aria-describedby. The border turns red and the focus halo follows, but the message and its icon carry the meaning — never color alone.
Disabled and read-only
Use disabled when a value can't be changed right now; it is skipped by keyboard focus and left out of form submissions. Use readOnly when people need to see, select or copy a value they can't edit — it stays focusable and is submitted with the form.
Contact your admin to change plans.
Read-only values stay focusable and selectable.
File
File inputs get a quiet, bordered selector button that matches the field. For drag-and-drop or multiple files with previews, build on top of this rather than replacing the native input — it keeps keyboard and assistive technology support for free.
PNG or JPG, up to 2 MB.
With a button
Because heights are shared, an input and a button sit side by side without adjustment. Give the input an aria-label when there is no visible label.
Controlled
Pass value and onChange to derive UI from what people type — here, a character count and a live URL preview. Prefer uncontrolled inputs with defaultValue when you only need the value on submit.
prfct.dev/quarterly-planning18/32
Guidelines
When to use
- Short, free-form text on a single line: names, emails, URLs, amounts, search queries.
- Values with a native type the browser already understands:
email,number,date,url,password.
When not to use
- Paragraphs or multi-line text — use a Textarea.
- Choosing from a known list — use a Select or, for long lists, a Combobox.
- Fixed-length codes such as 2FA — use Input OTP.
- Icons, units or buttons inside the field — use an Input Group.
Labels, not placeholders
A placeholder disappears the moment someone starts typing, so it can't carry the field's name or instructions. Put the name in a visible label, instructions in a description, and use the placeholder — if at all — for an example of the expected format.
Width is a hint
The width of a field tells people how much to type. Size fields to their expected content — a postal code should look shorter than an address — instead of stretching every input to the container.
Validate at the right moment
Validate on submit and when a field loses focus — not on every keystroke, which flags people as wrong before they have finished typing. Once a field is invalid, re-validate as they type so the error clears the moment it is fixed. See Field for the full pattern.
Accessibility
Input renders a native <input> through Base UI, so it keeps every browser behavior — autofill, spellcheck, IME composition, form submission — and works inside Base UI's Field and Form when you need built-in validation.
- Name every input. Associate a visible label with
htmlFor/id, or give inputs without a visible label anaria-label. - Describe and explain. Link descriptions and errors with
aria-describedby; setaria-invalidwhile a value is invalid. - Identify purpose. Set
autoCompleteon personal data such asname,emailandtel(WCAG 1.3.5). - Contrast. The field border uses the
inputtoken, which meets 3:1 against the page for non-text contrast (WCAG 1.4.11). Placeholder text usesmuted-foregroundat 4.5:1 or more. - No zoom on focus. Text is 16px below the
mdbreakpoint so iOS Safari doesn't zoom the page when the field is focused, then 14px on larger screens.
| Key | Behavior |
|---|---|
Tab | Moves focus to the input. Focus shows as a brand-colored border with a soft halo. |
ShiftTab | Moves focus to the previous focusable element. |
Enter | Submits the enclosing form. |
API reference
Input
Renders an <input> element. Accepts every native input attribute and the props of the Base UI Input. The native size attribute is replaced by prfct's size variant.
inputVariants
The class generator is exported for elements that should look like an input — for example a read-only value rendered as a <div>.
import { inputVariants } from "@/components/ui/input"
import { cn } from "@/lib/utils"
<div className={cn(inputVariants({ size: "sm" }), "flex items-center font-mono")}>
ws_8f3k29d1
</div>