Skip to content
Design System
Contact

Input

Text fields with labels, helper text, addons and inline validation.

Components<input>InputGroup

Playground

A field is a label, a control and one line of helper or error text. Addons sit inside the same border through InputGroup, so focus and error rings wrap the whole thing.

Preview

We send the invite to this address.

Props

Type
Size
Trailing
example.tsxtsx
1import { Mail } from "lucide-react"
2import { InputGroup, InputGroupInput, InputGroupAddon } from "@/components/ui/input-group"
3import { Label } from "@/components/ui/label"
4
5<div className="grid gap-1.5">
6 <Label htmlFor="work-email">
7 Work email
8 <span aria-hidden className="text-destructive">*</span>
9 </Label>
10 <InputGroup>
11 <InputGroupInput id="work-email" type="email" placeholder="name@company.com" required aria-describedby="work-email-help" />
12 <InputGroupAddon>
13 <Mail />
14 </InputGroupAddon>
15 </InputGroup>
16 <p id="work-email-help" className="text-xs text-muted-foreground">
17 We send the invite to this address.
18 </p>
19</div>

States

Validation shows after blur or submit, never on the first keystroke. Loading keeps the value editable and says what is being checked; success is quiet and only used when the check is meaningful.

States
  • We send the invite here.

    Defaultrest
  • We send the invite here.

    Hover:hover
  • We send the invite here.

    Focus:focus-visible
  • Checking the address…

    Loadingaria-busy
  • Managed by your identity provider.

    Disableddisabled
  • Finish the domain, like maya@acme.com.

    Erroraria-invalid
  • Address verified.

    Successdata-state=success

Patterns

Working compositions. Every one keeps a visible label (or an sr-only one for search) and connects its helper, counter or rules with aria-describedby.

Password with show and hide
  • At least 8 characters, not met yet
  • One number, not met yet
  • One symbol, not met yet
Search with shortcut hint
⌘K
  • Acme Corporation
  • Northwind
  • Globex
  • Initech

7 of 7 companies. Press / to jump here.

Character counter
Shown on the project page108 characters left

Keep it to one or two sentences.

Prefix and suffix addons
$
USD

Formats to two decimals when you leave the field.

acme.app/

Lowercase letters, numbers and dashes. Opens at https://acme.app/northwind

Helper text wired with aria-describedby

Shown on invoices and in the client portal.

Screen reader announces

Company name, required, edit text, blank. Shown on invoices and in the client portal.

API

Input is a styled native input and forwards every input attribute. InputGroup composes addons around InputGroupInput or InputGroupTextarea.

PropTypeDefaultDescription
type"text" | "email" | "password" | "search" | …"text"Native input type. Pick the one that brings the right mobile keyboard and autofill.
aria-invalidboolean—Turns the border and ring destructive. Pair with an error message referenced by aria-describedby.
aria-describedbystring—Ids of the helper, error or counter text that the screen reader reads after the label.
classNamestring—Size through height: h-7 small, h-8 default, h-9 large. Put it on InputGroup when using addons.
InputGroupAddon align"inline-start" | "inline-end" | "block-start" | "block-end""inline-start"Where the addon sits. Clicking an addon focuses the input.
InputGroupButton size"xs" | "sm" | "icon-xs" | "icon-sm""xs"Compact ghost button inside the field, e.g. clear, copy or reveal.
InputGroupTextReactNode—Static prefix or suffix text such as $, USD or a domain.
InputGroupTextareatextarea props—Auto-growing textarea that shares the group border, for counters and toolbars.

Accessibility

Keyboard

Move to the next field or addon button
Tab
Clear the search field
Esc
Jump to search (demo)
/
Submit the surrounding form
Enter

Semantics and ARIA

  • Every input has a <Label htmlFor>. A placeholder is an example, not a label; it disappears on typing and has low contrast.
  • Helper and error text are linked with aria-describedby, so they are read after the label. The error replaces the helper rather than stacking under it.
  • Errors set aria-invalid, use an icon plus text (never color alone) and say how to fix the value.
  • Addon icons are decorative and hidden from assistive tech. Addon buttons are real buttons with an aria-label; the reveal toggle uses aria-pressed with a stable label.
  • Inputs use 16px text below the md breakpoint so iOS does not zoom on focus, and set autoComplete and inputMode for autofill and the right keyboard.
  • Required fields use the native required attribute; the asterisk is aria-hidden because the attribute is already announced.