A styled native HTML input element. It accepts every standard input attribute and has built-in styles for focus,
disabled, invalid (aria-invalid) and file states. Icons, loading indicators and buttons (such as a password
visibility toggle) are composed with InputGroup.
Features
Plain native input — all HTML input attributes and types are supported
Focus ring, disabled and aria-invalid error styling out of the box
A FieldDescription below the input explains what the value is used for.
import { Field, FieldDescription, FieldLabel } from '@/components/ui/field'import { Input } from '@/components/ui/input'export function InputWithDescription() { return ( <Field> <FieldLabel htmlFor="input-email">Email</FieldLabel> <Input type="email" id="input-email" autoComplete="email" placeholder="sofia.berg@example.se" /> <FieldDescription>We send receipts and decisions about your application here.</FieldDescription> </Field> )}
Address
Several inputs in a FieldSet, with autoComplete hints so browsers can fill in the address.
import { Field, FieldDescription, FieldGroup, FieldLabel, FieldLegend, FieldSet,} from '@/components/ui/field'import { Input } from '@/components/ui/input'export function InputAddress() { return ( <FieldSet> <FieldLegend>Property address</FieldLegend> <FieldDescription>The address where the new bins should be delivered.</FieldDescription> <FieldGroup className="gap-4"> <Field> <FieldLabel htmlFor="input-street">Street address</FieldLabel> <Input id="input-street" autoComplete="street-address" defaultValue="Storgatan 14" /> </Field> <div className="grid grid-cols-[7rem_1fr] gap-3"> <Field> <FieldLabel htmlFor="input-postcode">Postal code</FieldLabel> <Input id="input-postcode" autoComplete="postal-code" inputMode="numeric" defaultValue="722 15" /> </Field> <Field> <FieldLabel htmlFor="input-city">City</FieldLabel> <Input id="input-city" autoComplete="address-level2" defaultValue="Västerås" /> </Field> </div> </FieldGroup> </FieldSet> )}
With Button
An input and a button side by side.
import { Button } from '@/components/ui/button'import { Field, FieldLabel } from '@/components/ui/field'import { Input } from '@/components/ui/input'export function InputWithButton() { return ( <Field> <FieldLabel htmlFor="input-newsletter">Get council meeting agendas by email</FieldLabel> <div className="flex gap-2"> <Input id="input-newsletter" type="email" autoComplete="email" placeholder="name@example.se" /> <Button variant="outline">Subscribe</Button> </div> </Field> )}
Disabled
import { Field, FieldDescription, FieldLabel } from '@/components/ui/field'import { Input } from '@/components/ui/input'export function InputDisabled() { return ( <Field data-disabled="true"> <FieldLabel htmlFor="input-disabled">Personal identity number</FieldLabel> <Input id="input-disabled" placeholder="YYYYMMDD-XXXX" disabled /> <FieldDescription>Filled in automatically when you sign in with e-ID.</FieldDescription> </Field> )}
Readonly
Read-only inputs get a dashed border and a muted background.
import { Field, FieldDescription, FieldLabel } from '@/components/ui/field'import { Input } from '@/components/ui/input'export function InputReadonly() { return ( <Field> <FieldLabel htmlFor="input-readonly">Registered by</FieldLabel> <Input readOnly id="input-readonly" defaultValue="Mikko Virtanen, Registry" /> <FieldDescription>Set when the case was registered on 14 April 2026.</FieldDescription> </Field> )}
Invalid
Set aria-invalid to show the destructive border and ring, and point aria-describedby at the error message.
import { Field, FieldError, FieldLabel } from '@/components/ui/field'import { Input } from '@/components/ui/input'export function InputInvalid() { return ( <Field data-invalid="true"> <FieldLabel htmlFor="input-invalid">Vehicle registration number</FieldLabel> <Input id="input-invalid" defaultValue="ABC 12" aria-invalid aria-describedby="input-invalid-error" /> <FieldError id="input-invalid-error">Use three letters and three characters, e.g. ABC 123 or ABC 12D.</FieldError> </Field> )}
File Input
import { Field, FieldDescription, FieldLabel } from '@/components/ui/field'import { Input } from '@/components/ui/input'export function InputFile() { return ( <Field> <FieldLabel htmlFor="input-file">Site plan</FieldLabel> <Input id="input-file" type="file" accept=".pdf,.dwg" /> <FieldDescription>PDF or DWG, scale 1:400 or 1:500.</FieldDescription> </Field> )}
With Validation
Client-side validation of a case number that toggles aria-invalid once the value is complete.
import * as React from 'react'import { Field, FieldDescription, FieldError, FieldLabel } from '@/components/ui/field'import { Input } from '@/components/ui/input'export function InputWithValidation() { const [value, setValue] = React.useState('') const valid = /^\d{4}-\d{5}$/.test(value) const showError = value.length >= 10 && !valid return ( <Field data-invalid={showError || undefined}> <FieldLabel htmlFor="input-validation">Case number</FieldLabel> <Input id="input-validation" placeholder="2026-04812" inputMode="numeric" maxLength={10} value={value} onChange={(event) => setValue(event.target.value)} aria-invalid={showError || undefined} aria-describedby="input-validation-hint" /> {showError ? ( <FieldError id="input-validation-hint">Case numbers are a year, a dash and five digits.</FieldError> ) : ( <FieldDescription id="input-validation-hint"> {valid ? 'Looks good — press Enter to open the case.' : 'A year, a dash and five digits.'} </FieldDescription> )} </Field> )}