Input
A styled Base UI input for every text-entry type — Field-aware state, invalid and disabled chrome, and a subtle darker border instead of a focus ring.
- Status
- Since
0.1.0- Accessibility pattern
- native input
Last updated
Install
Configure registry credentials first using the Quickstart. Before copying this item or any transitive registry dependency, verify the signed manifest and save the exact bytes for Input before installation. Retain the digest printed by this command.
pnpm exec vegastack-design verify inputInstall with the pinned shadcn CLI. Bare shadcn does not verify VegaStack signature or integrity.
pnpm dlx shadcn@4.21.0 add @vegastack/inputRun the exact offline --post-write command printed by the preflight, using its saved item path and independently retained --expected-integrity digest. Use the saved preflight for every transitive registry dependency too; stop on any mismatch before using the components.
Usage
import { Input } from "@/components/ui/input";
<Input />;Examples
Basic
A bare input with a placeholder.
Sizes
size="sm" is 28px, default 32px, and lg sets heading type — pair it with ghost for a big
title.
Ghost
variant="ghost" drops the border and the fill, so the text sits on the page like a heading — the
title field of a new-issue dialog. It paints no fill in any state — rest, hover or focus: the text
cursor shows it is editable, the caret is the focus cue, and an invalid ghost field turns its
placeholder destructive.
<Input variant="ghost" size="lg" placeholder="Issue title" aria-label="Title" />Field
Field, FieldLabel and FieldDescription give the input a label and helper text.
Choose a unique username for your account.
Field Group
FieldGroup stacks several Field blocks and is how a form is built.
We'll send updates to this address.
Disabled
Use disabled, and add data-disabled to the Field so the label dims with it. The input keeps
disabled:cursor-not-allowed.
This field is currently disabled.
Invalid
Use aria-invalid, and add data-invalid to the Field. The destructive border holds in every
state: focus never replaces it with the darker focus border (FOC-14).
File
type="file" styles the native file button with the file: variants.
Select a picture to upload.
Inline
Field with orientation="horizontal" puts the input and a Button on one row.
Grid
A FieldGroup with a grid layout places two inputs side by side.
Required
required marks the field for the platform's own validation.
This field must be filled out.
Badge
A Badge inside the label highlights a beta or recommended field.
Input Group
For an icon, a text prefix or a button on the same surface, use Input Group.
Button Group
For a button joined to the field's edge, use Button Group.
Form
Several inputs, a select and a submit row.
RTL
Padding is written in logical properties, so a right-to-left document mirrors the control without any extra work.
As it appears on your passport.
كما يظهر في جواز سفرك.
Not a credential
A field that holds a record's name — a table, a field, a page title — is not a login, but password
managers offer to fill any name-like input. credential={false} turns that off
(autoComplete="off" and the 1Password, LastPass and Bitwarden ignore markers); an explicit
autoComplete still wins.
<Input
credential={false}
aria-label="Table name"
defaultValue="Sample requests"
/>States
Rest, filled, invalid and disabled in one frame. Click or Tab into a field to see the focus state: the
border darkens subtly (border-ring/50) over 150ms and no fill is painted; the invalid field keeps
its destructive border while focused.
Playground
Try every type with the disabled and invalid states, then copy the generated JSX.
<Input placeholder="you@vegastack.com" />API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
credential | boolean | true | false (FRM-17) marks a name-like field that is not a credential — a record, table or field
name — so browsers and password managers stop offering to fill it: autoComplete="off",
data-1p-ignore, data-lpignore="true", data-bwignore. An explicit autoComplete wins. |
size | "default" | "lg" | "sm" | null | — | |
variant | "default" | "ghost" | null | — |
Accessibility
- Renders Base UI's Input, which is a native
<input>wired to the surroundingField, so the platform owns selection, IME composition and autofill. - Focus is a subtle darker border (
border-ring/50, easing in over 150ms), not a ring, and no background change — text entry is the one exception to FOC-14's fixed border (MK 2026-09-27); the global outline is suppressed withoutline-hidden(FOC-8). It fires on:focus, for mouse and keyboard alike, because a text field cannot tell them apart and both need the caret located. An invalid field keeps its destructive border while focused.type="file"is a button, so it keeps the global background tint instead. - Under
forced-colors: activethe border colour is replaced with every authored colour, sobase.csspaints a 2pxHighlightoutline oninput:focusinstead (FOC-7). - Give it a label:
FieldLabelbound withhtmlFor, or anaria-label.
| Contract | States tested |
|---|---|
| Behaviour | default, disabled, invalid, readonly |
| Accessibility | native-or-base-ui-semantics, browser-accessibility-test, invalid, disabled |
| Visual | default, focus, invalid, disabled |
Do / Don't
Deviations
Upstream's file plus packages/ui/upstream/patches/input.patch. Every hunk:
- FOC-1, FOC-3, FOC-6, FOC-8 —
outline-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50becomesoutline-hidden, with no ring and no glow.outline-hiddenrather thanoutline-none, so the forced-colours fallback has something to repaint. - FOC-14 — the invalid border is
aria-invalid:border-destructive(and its dark counterpart), held in every state, focused or not; thearia-invalidhalo rings are removed with the rest. - FOC-14 text-entry exception (MK 2026-09-27) — the default variant adds
focus:not-aria-invalid:not-[[type=file]]:border-ring/50withtransition-[color,background-color,border-color] duration-150 ease-out: a subtle darker border that eases in, and no fill (base.cssexcludes text inputs from the background tint). Thenot-aria-invalidguard keeps the destructive border; a file input is a button and keeps the tint. The ghost variant has no border and no focus fill — the caret is the cue. - FRM-4 —
disabled:pointer-events-noneis dropped, so a disabled input stays hoverable and a Tooltip can explain it. Base UI's Input has nofocusableWhenDisabled, so the nativedisabledattribute stays: this is the pointer half of FRM-4 only. - API-26 — NO HUNK: Base UI's
InputisField.Control, so inside aFieldit already takes its label, the rendered description and error ids, andaria-invalidfrom the Field. - DOC-2 —
cnis imported from@vegastack/design. - FRM-17 —
Inputtakescredential;falsemarks a non-credential name field so password managers leave it alone. MK, 2026-10-26.