Skip to content

Form components

The core form controls ship in every Pelagic UI package. Labels are always linked, hints and errors are announced through aria-describedby, and invalid fields set aria-invalid.

9 components on this page. Every demo is live — change the theme in the header or flip a demo to right-to-left with its RTL button.

Button Link to Button

Five variants, three sizes, a loading state with aria-busy and icon-only buttons with an accessible name.

Live demo

Props

PropTypeDescription
variant 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger' Visual style. Default primary.
size 'sm' | 'md' | 'lg' Control height and padding.
loading boolean Shows a spinner, sets aria-busy and disables the button.
block boolean Full width.
iconOnly boolean Square button for a single icon. Pass aria-label.

Accessibility

Button keyboard support
KeyAction
Enter / Space Activates the button
Tab Moves focus to the next control

Native <button> element, so focus, disabled and form submission behave as browsers expect.

Code

Button · React
<Button>Save</Button>
<Button variant="outline">Preview</Button>
<Button variant="danger" loading>Deleting</Button>

Input Link to Input

A labelled text field with hint and error messages wired to aria-describedby.

Live demo
As it appears on your ID
Enter a valid email address

Props

PropTypeDescription
label string Visible label linked with htmlFor.
hint string Helper text under the field.
error string Error text. Sets aria-invalid and replaces the hint.
…input attributes InputHTMLAttributes type, value, onChange, placeholder, autoComplete, etc.

Accessibility

Input keyboard support
KeyAction
Tab Moves focus into and out of the field

Errors replace the hint so screen readers announce a single, current message.

Code

Input · React
const [email, setEmail] = useState('');
<Input label="Email" type="email" value={email}
  onChange={(e) => setEmail(e.target.value)}
  error={email ? undefined : 'Required'} />

Textarea Link to Textarea

Multi-line text with the same label, hint and error wiring as Input.

Live demo
0/280 characters

Props

PropTypeDescription
label string Visible label.
hint / error string Helper or error message.
rows number Initial visible rows.

Accessibility

Textarea keyboard support
KeyAction
Tab Moves focus; Enter inserts a new line

Code

Textarea · React
<Textarea label="Project brief" rows={4} value={brief}
  onChange={(e) => setBrief(e.target.value)} hint="Markdown supported" />

Select Link to Select

A native select with a styled trigger, placeholder option and linked label.

Live demo

Selected: none

Props

PropTypeDescription
options { label, value, disabled? }[] Choices to render.
placeholder string Empty first option.
label / hint / error string Field metadata.

Accessibility

Select keyboard support
KeyAction
Arrow Up / Arrow Down Changes the selected option
Alt + Arrow Down Opens the native list

Uses the native <select>, so mobile pickers and assistive technology work out of the box.

Code

Select · React
<Select label="Team" placeholder="Choose a team" value={team}
  onChange={(e) => setTeam(e.target.value)}
  options={[{ label: 'Design', value: 'design' }, { label: 'Engineering', value: 'eng' }]} />

Checkbox Link to Checkbox

A native checkbox with a visible, clickable label.

Live demo

Props

PropTypeDescription
label ReactNode Label text.
checked / onChange boolean / ChangeEvent Controlled state.
disabled boolean Disables the control.

Accessibility

Checkbox keyboard support
KeyAction
Space Toggles the checkbox

Code

Checkbox · React
<Checkbox label="Email me updates" checked={updates}
  onChange={(e) => setUpdates(e.target.checked)} />

Switch Link to Switch

An on/off toggle using role="switch" with aria-checked.

Live demo

Dark previews: On

Props

PropTypeDescription
checked boolean Current state.
onChange (checked: boolean) => void Called on toggle.
label string Accessible name (required).
disabled boolean Disables the switch.

Accessibility

Switch keyboard support
KeyAction
Space / Enter Toggles the switch

Code

Switch · React
<Switch label="Dark previews" checked={dark} onChange={setDark} />

RadioGroup Link to RadioGroup

A fieldset of radio buttons with a legend; one option can be chosen.

Live demo

Plan: pro

Props

PropTypeDescription
name string Shared input name.
options { label, value, disabled? }[] Choices.
value / onChange string / (value) => void Controlled selection.
label string Legend text.

Accessibility

RadioGroup keyboard support
KeyAction
Arrow keys Move selection between options
Tab Moves into and out of the group

Code

RadioGroup · React
<RadioGroup name="plan" label="Plan" value={plan} onChange={setPlan}
  options={[{ label: 'Free', value: 'free' }, { label: 'Pro', value: 'pro' }]} />

Slider Link to Slider

A range input with an optional live value readout.

Live demo

Props

PropTypeDescription
value / onChange number / (value) => void Controlled value.
min / max / step number Range. Defaults 0, 100, 1.
label string Visible label.
showValue boolean Shows the current value next to the label.

Accessibility

Slider keyboard support
KeyAction
Arrow keys Change by one step
Page Up / Page Down Change by a larger step
Home / End Jump to min / max

Code

Slider · React
<Slider label="Budget" value={budget} onChange={setBudget} showValue />

Segmented Link to Segmented

A compact single-choice control for switching views.

Live demo

View: grid

Props

PropTypeDescription
options { label, value }[] Segments.
value / onChange string / (value) => void Controlled selection.
label string Accessible group name (required).

Accessibility

Segmented keyboard support
KeyAction
Arrow keys Move between segments

Built from native radio inputs inside a labelled group.

Code

Segmented · React
<Segmented label="View" value={view} onChange={setView}
  options={[{ label: 'Grid', value: 'grid' }, { label: 'List', value: 'list' }]} />

Search Pelagic UI