Skip to content

Advanced form inputs

Rich inputs that follow the WAI-ARIA combobox, listbox, slider and grid patterns. They accept the same label, hint and error props as the core fields, so validation looks and sounds the same everywhere.

20 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. These components are React-only for now; Vue, Svelte and Angular versions are coming.

AutoComplete Link to AutoComplete

A combobox that suggests matches as you type, with single or multiple (chip) selection.

Live demo
Try Arrow Down after typing
ReactTypeScript

Selected: — · React, TypeScript

Props

PropTypeDescription
suggestions FormOption[] Options; filtered locally unless you handle onSearch.
onSearch (query) => void Fetch remote suggestions.
multiple boolean Pick several values shown as removable chips.
onSelect (option) => void Called when an option is chosen.
loading / minLength boolean / number Loading message and minimum query length.

Accessibility

AutoComplete keyboard support
KeyAction
Arrow Down / Arrow Up Move the active option
Home / End First / last option
Enter Select the active option
Escape Close the list and return focus
Backspace Removes the last chip when the input is empty (multiple)

role="combobox" with aria-expanded and aria-activedescendant; the result count is announced in a live region.

Code

ReactComing to Vue, Svelte and Angular.

AutoComplete · React
const countries = [{ label: 'Jordan', value: 'jo' }, { label: 'Japan', value: 'jp' }];

<AutoComplete label="Country" suggestions={countries}
  onSelect={(o) => setCountry(o.value)} placeholder="Start typing…" />

<AutoComplete label="Skills" multiple suggestions={skills}
  selected={picked} onSelectionChange={setPicked} />

MultiSelect Link to MultiSelect

A dropdown of checkable options with filter, select-all and chip display.

Live demo
Cities

Value: amman, dubai

Props

PropTypeDescription
options FormOption[] Choices.
value / onChange string[] Selected values.
filter boolean Adds a search box to the panel.
display 'comma' | 'chip' How the selection is summarised.
showSelectAll / maxSelectedLabels boolean / number Bulk selection and summary threshold.

Accessibility

MultiSelect keyboard support
KeyAction
Arrow Down / Arrow Up Move the active option
Home / End First / last option
Enter Select the active option
Escape Close the list and return focus
Space Toggle the active option

The panel is a multi-select listbox (aria-multiselectable) and the trigger reports how many items are selected.

Code

ReactComing to Vue, Svelte and Angular.

MultiSelect · React
<MultiSelect label="Cities" options={cities} value={value} onChange={setValue}
  filter display="chip" showSelectAll maxSelectedLabels={3} />

Listbox Link to Listbox

An always-visible list of options with single or multiple selection and filtering.

Live demo
Timezone
  • GMT−5 · New York
  • GMT+0 · London
  • GMT+1 · Paris
  • GMT+3 · Amman
  • GMT+4 · Dubai
  • GMT+9 · Tokyo

Timezone: gmt+3

Props

PropTypeDescription
options FormOption[] Choices.
multiple boolean Allow several values.
value / onChange string | string[] | null Selection.
filter boolean Adds a search box.
ariaLabel string Accessible name when there is no label.

Accessibility

Listbox keyboard support
KeyAction
Arrow Down / Arrow Up Move focus
Home / End First / last option
Space / Enter Select the focused option

Code

ReactComing to Vue, Svelte and Angular.

Listbox · React
<Listbox label="Timezone" options={zones} value={zone} onChange={setZone} filter />

CascadeSelect Link to CascadeSelect

Pick a leaf from nested groups — e.g. country, then state, then city.

Live demo
Office

Office: none

Props

PropTypeDescription
options CascadeOption[] Nested { label, value?, children? }.
value / onChange string | null Selected leaf value.
placeholder string Trigger text when empty.

Accessibility

CascadeSelect keyboard support
KeyAction
Arrow Down / Arrow Up Move the active option
Home / End First / last option
Enter Select the active option
Escape Close the list and return focus
Arrow Right / Arrow Left Open / close a sub-group (mirrored in RTL)

Code

ReactComing to Vue, Svelte and Angular.

CascadeSelect · React
<CascadeSelect label="Office" options={[
  { label: 'Jordan', children: [{ label: 'Amman', value: 'amm' }, { label: 'Irbid', value: 'irb' }] },
  { label: 'UAE', children: [{ label: 'Dubai', value: 'dxb' }] },
]} value={office} onChange={setOffice} />

TreeSelect Link to TreeSelect

A dropdown containing a tree, for single or checkbox selection of hierarchical data.

Live demo
Folders

Keys: tokens

Props

PropTypeDescription
nodes TreeSelectNode[] { key, label, children? } tree.
selectionMode 'single' | 'checkbox' Single pick or multiple with tri-state parents.
value / onChange string | string[] | null Selected keys.
defaultExpandedKeys string[] Initially expanded branches.

Accessibility

TreeSelect keyboard support
KeyAction
Arrow Down / Arrow Up Move the active option
Home / End First / last option
Enter Select the active option
Escape Close the list and return focus
Arrow Right / Arrow Left Expand / collapse a branch

Code

ReactComing to Vue, Svelte and Angular.

TreeSelect · React
<TreeSelect label="Folders" nodes={folders} selectionMode="checkbox"
  value={keys} onChange={setKeys} defaultExpandedKeys={['docs']} />

InputNumber Link to InputNumber

Locale-aware numeric input with currency, percent, min/max and spin buttons.

Live demo

Total: $3,750.00

Props

PropTypeDescription
value / onChange number | null Numeric value.
mode 'decimal' | 'currency' | 'percent' Formatting style.
currency / locale string e.g. "USD", "ar-JO".
min / max / step number Bounds and increment.
showButtons boolean Adds increment / decrement buttons.

Accessibility

InputNumber keyboard support
KeyAction
Arrow Up / Arrow Down Increment / decrement by step
Page Up / Page Down Larger steps
Home / End Jump to min / max

role="spinbutton" with aria-valuenow, aria-valuemin and aria-valuemax; the formatted value is exposed as aria-valuetext.

Code

ReactComing to Vue, Svelte and Angular.

InputNumber · React
<InputNumber label="Price" mode="currency" currency="USD" value={price}
  onChange={setPrice} min={0} showButtons />
<InputNumber label="Discount" mode="percent" value={0.15} maxFractionDigits={1} />

InputMask Link to InputMask

Typed input that follows a pattern such as a phone number or card expiry.

Live demo

Phone: incomplete

Props

PropTypeDescription
mask string 9 = digit, a = letter, * = either. e.g. "(999) 999-9999".
value / onChange (value, { masked, complete }) Raw and masked value.
onComplete (value) => void Called when every slot is filled.
slotChar string Placeholder for empty slots. Default "_".

Accessibility

InputMask keyboard support
KeyAction
Backspace / Delete Clear the previous / next slot, skipping literals

Code

ReactComing to Vue, Svelte and Angular.

InputMask · React
<InputMask label="Phone" mask="(999) 999-9999" value={phone}
  onChange={(raw, { complete }) => { setPhone(raw); setDone(complete); }} />

InputOtp Link to InputOtp

One-time-code entry: one cell per character with an animated caret, grouping, SMS autofill, masking with reveal, a resend countdown and error / success states.

Live demo
Verification code
We sent a 6-digit code to •••• 4821. Try 123456.
Resend code in 0:30
Card PIN

Props

PropTypeDescription
length number Number of cells. Default 4.
value / onChange / onComplete string The code; onComplete fires when every cell is filled.
integerOnly boolean Digits only — opens the numeric keypad on phones.
groups / separator number[] / ReactNode e.g. [3, 3] renders 123 – 456.
mask / revealable boolean Hide characters, with a Show code toggle.
error / success string / boolean | string Error shakes the cells (not with reduced motion); success turns them green.
resendAfter / onResend number / () => void Countdown in seconds before Resend unlocks.

Accessibility

InputOtp keyboard support
KeyAction
Arrow Left / Arrow Right Move between cells
Backspace Clear and move back
Home / End First / last cell
Ctrl + V Paste a whole code from any cell

Each cell has its own label ("Digit 2 of 6") inside a labelled group; autocomplete="one-time-code" lets phones fill the SMS code. Errors are announced (role="alert") and success politely. Digits stay left-to-right in Arabic pages. Separators and the caret are decorative.

Code

ReactComing to Vue, Svelte and Angular.

InputOtp · React
<InputOtp label="Verification code" length={6} groups={[3, 3]} integerOnly
  resendAfter={30} onResend={sendAgain} error={wrong ? 'That code did not match' : undefined}
  onComplete={(code) => verify(code)} />

Password Link to Password

Password field with a show/hide toggle, strength meter and requirement checklist.

Live demo
  • At least 8 characters (not met)
  • A lowercase letter (not met)
  • An uppercase letter (not met)
  • A number (not met)

Props

PropTypeDescription
feedback boolean Shows the strength meter.
toggleMask boolean Adds a show / hide button.
requirements boolean | PasswordRequirement[] Live checklist of rules.
strengthLabels Record<strength, string> Localised "Weak / Medium / Strong".

Accessibility

Password keyboard support
KeyAction
Tab Moves between the field and the show / hide button

Strength changes are announced politely; the toggle button reports aria-pressed.

Code

ReactComing to Vue, Svelte and Angular.

Password · React
<Password label="New password" autoComplete="new-password"
  feedback toggleMask requirements value={pw} onChange={(e) => setPw(e.target.value)} />

Rating Link to Rating

Star rating built on radio buttons, with an optional clear button.

Live demo

Rating: 4 / 5

Props

PropTypeDescription
value / onChange number Selected stars.
stars number Number of stars. Default 5.
cancel boolean Shows a clear button.
readOnly / disabled boolean Display-only or disabled.

Accessibility

Rating keyboard support
KeyAction
Arrow keys Change the rating (mirrored in RTL)
Home / End Lowest / highest

Code

ReactComing to Vue, Svelte and Angular.

Rating · React
<Rating label="Your rating" value={stars} onChange={setStars} cancel />

Knob Link to Knob

A circular dial for picking a value in a range.

Live demo

Props

PropTypeDescription
value / onChange number Current value.
min / max / step number Range.
label string Accessible name (required).
valueTemplate string e.g. "{value}%".
size / strokeWidth number Dimensions in px.

Accessibility

Knob keyboard support
KeyAction
Arrow keys Change by one step
Page Up / Page Down Change by ten steps
Home / End Min / max

role="slider" with aria-valuetext built from valueTemplate. Drag works with mouse, pen and touch.

Code

ReactComing to Vue, Svelte and Angular.

Knob · React
<Knob label="Volume" value={volume} onChange={setVolume} valueTemplate="{value}%" />

ColorPicker Link to ColorPicker

A full colour picker: saturation / brightness area, hue and opacity sliders, HEX · RGB · HSL · OKLCH entry, eyedropper, presets, recent colours and a WCAG contrast check.

Live demo
Brand colour (popover)
Text colour (inline)
Contrast 6.70:1 on #ffffff AA pass AA Large pass AAA fail

Value: #5b34d6

Props

PropTypeDescription
value / onChange string Any CSS colour in; emits #rrggbb (or #rrggbbaa with alpha).
onColorChange ({ hex, rgba, css }) => void Rich change event.
mode 'popover' | 'inline' Swatch button with a popover (default), or always visible.
alpha boolean Opacity slider.
formats / format ('hex' | 'rgb' | 'hsl' | 'oklch')[] Text formats offered by the format switch.
presets / recent Array<string | { value, label }> / number Swatches and how many recent colours to keep.
contrastWith string Background to check against: shows the ratio and AA / AA Large / AAA pass or fail.
eyeDropper boolean Pick from the screen where the EyeDropper API exists.

Accessibility

ColorPicker keyboard support
KeyAction
Arrow Left / Arrow Right Saturation (area) or value (sliders); Shift = 10 steps
Arrow Up / Arrow Down Brightness (area) or value (sliders)
Page Up / Page Down Large steps
Home / End Minimum / maximum
Escape Close the popover and return to the swatch button

The area is a slider whose aria-valuetext reads "Saturation 40%, Brightness 70%"; the hue slider names the colour ("210 degrees, blue"). Swatches are toggle buttons with labels, and the contrast grades are written out, so nothing depends on seeing colour.

Code

ReactComing to Vue, Svelte and Angular.

ColorPicker · React
<ColorPicker label="Brand colour" value={color} onChange={setColor} alpha
  contrastWith="#ffffff" presets={[{ value: '#5b34d6', label: 'Violet' }, { value: '#0f766e', label: 'Teal' }]} />

DatePicker Link to DatePicker

Typed or calendar date entry with ranges, multiple dates, time and min/max limits.

Live demo
Format: YYYY-MM-DD
Format: YYYY-MM-DD
Weekdays only
Inline calendar

October 2026

SunMonTueWedThuFriSat
123
45678910
11121314151617
18192021222324
25262728293031

Trip: none

Props

PropTypeDescription
value / onChange Date | Date[] | null Selection.
selectionMode 'single' | 'range' | 'multiple' What a click selects.
minDate / maxDate / disabledDays Date / number[] Restrict choices.
inline boolean Always-visible calendar.
showTime / showButtonBar boolean Time inputs and Today / Clear buttons.
locale / firstDayOfWeek string / number Localisation (works with ar-JO, etc.).

Accessibility

DatePicker keyboard support
KeyAction
Arrow keys Move by day / week
Page Up / Page Down Previous / next month
Home / End Start / end of the week
Enter Select the focused day
Escape Close the calendar

The calendar is a grid with labelled days; the month change is announced.

Code

ReactComing to Vue, Svelte and Angular.

DatePicker · React
<DatePicker label="Trip dates" selectionMode="range" value={range}
  onChange={setRange} minDate={new Date()} showButtonBar />
<DatePicker label="Meeting" showTime value={when} onChange={setWhen} />

ToggleButton Link to ToggleButton

A button that stays pressed, reporting aria-pressed.

Live demo

Bold: not pressed

Props

PropTypeDescription
checked / onChange boolean Pressed state.
onLabel / offLabel ReactNode Text for each state.
onIcon / offIcon ReactNode Icons for each state.

Accessibility

ToggleButton keyboard support
KeyAction
Space / Enter Toggle

Code

ReactComing to Vue, Svelte and Angular.

ToggleButton · React
<ToggleButton checked={bold} onChange={setBold} onLabel="Bold on" offLabel="Bold off" />

SelectButton Link to SelectButton

A row of buttons acting as single or multiple choice.

Live demo

Value: monthly · b

Props

PropTypeDescription
options FormOption[] Choices.
value / onChange string | string[] | null Selection.
multiple boolean Allow several.
allowEmpty boolean Allow deselecting the last one.
label string Group name (required).

Accessibility

SelectButton keyboard support
KeyAction
Tab Move between buttons
Space / Enter Toggle the focused option

Code

ReactComing to Vue, Svelte and Angular.

SelectButton · React
<SelectButton label="Text style" multiple options={[
  { label: 'Bold', value: 'b' }, { label: 'Italic', value: 'i' }, { label: 'Underline', value: 'u' },
]} value={styles} onChange={setStyles} />

FloatLabel Link to FloatLabel

A label that sits inside the field and floats above it on focus or when filled.

Live demo

Props

PropTypeDescription
label ReactNode Label text.
children ReactElement One input-like element; it gets an id automatically.
variant 'over' | 'in' | 'on' Where the label rests.

Accessibility

A real <label> linked with htmlFor — not a placeholder — so the name never disappears.

Code

ReactComing to Vue, Svelte and Angular.

FloatLabel · React
<FloatLabel label="Username">
  <input className="pl-input" value={user} onChange={(e) => setUser(e.target.value)} />
</FloatLabel>

IftaLabel Link to IftaLabel

An "infield top-aligned" label that is always visible inside the top of the field.

Live demo

Props

PropTypeDescription
label ReactNode Label text.
children ReactElement One input-like element.

Accessibility

Code

ReactComing to Vue, Svelte and Angular.

IftaLabel · React
<IftaLabel label="Email">
  <input className="pl-input" type="email" />
</IftaLabel>

InputGroup Link to InputGroup

Joins addons (text, icons, buttons) to the sides of a field.

Live demo
https://
$.00

Props

PropTypeDescription
InputGroup HTMLAttributes<div> Wrapper.
InputGroupAddon HTMLAttributes<span> Static text or icon on either side.

Accessibility

Addons are visual. Put essential information (like a currency) in the input’s label too.

Code

ReactComing to Vue, Svelte and Angular.

InputGroup · React
<InputGroup>
  <InputGroupAddon>https://</InputGroupAddon>
  <input className="pl-input" aria-label="Website" />
  <Button>Go</Button>
</InputGroup>

IconField Link to IconField

Places a decorative icon inside a field, at the start or end.

Live demo

Props

PropTypeDescription
iconPosition 'start' | 'end' Logical side; mirrors in RTL.
InputIcon HTMLAttributes<span> The icon. Hidden from assistive tech.

Accessibility

Code

ReactComing to Vue, Svelte and Angular.

IconField · React
<IconField iconPosition="start">
  <InputIcon>🔍</InputIcon>
  <input className="pl-input" type="search" aria-label="Search" />
</IconField>

KeyFilter Link to KeyFilter

Blocks characters that don’t match a pattern, both when typed and pasted.

Live demo
Digits only (Arabic-Indic too)
0–9 and a–f
Letters only

Props

PropTypeDescription
keyFilterProps(pattern) (pattern) => handlers Spread onto any input.
useKeyFilter(pattern) hook Memoised version.
pattern 'pint' | 'int' | 'num' | 'alpha' | 'alphanum' | 'hex' | RegExp Allowed characters. Digits include Arabic-Indic numerals.

Accessibility

Pair it with a hint that says what is allowed, so blocked keys are not a surprise.

Code

ReactComing to Vue, Svelte and Angular.

KeyFilter · React
const digits = useKeyFilter('pint');
<Input label="Quantity" hint="Digits only" inputMode="numeric" {...digits} />

Search Pelagic UI