A single binary control representing list-membership ("include this item") or feature-flag state ("agree to terms"). Use Checkbox when the semantic is "select / deselect"; use Switch when the semantic is "enable / disable a feature." Pair with `field` for the label.
Readiness
complete
Preview
live
Props
5
Examples
2
Code
implementation mapped
When to use
Selecting an item in a list (CheckboxGroup variant)
Agreeing to terms / consenting
Toggling a binary preference where the verb is 'select'
Indeterminate parent states for nested lists
When not to use
Toggling a feature on / off — use Switch
Mutually-exclusive choices — use Radio / RadioGroup
Multiple items from a small set — use CheckboxGroup, not multiple Checkboxes manually
Accessibility
Role: checkbox
Space — Toggles the checkbox
Tab — Focus to/from the checkbox
Screen reader: Announces `checked=true|false` and `aria-required=true` if required. Indeterminate state announces as 'mixed'.
Notes: Pair with `field` so the visible label is wired via `for`/`id`. A bare label adjacent to a checkbox is not enough — SR users need the explicit association.
Props
Name
Type
Default
Description
checked
boolean
—
on_change
string
—
label
string
—
Visible label rendered next to the checkbox.
disabled
boolean
false
indeterminate
boolean
false
Renders the mixed-state visual (parent of partially-checked children).
Examples
Remember me
Remember-me toggle on a login form.
YAML
type: checkbox
props:
checked: ${state.remember_me}
on_change: ${actions.toggle_remember_me}
label: Remember me
Indeterminate
Indeterminate parent state.
YAML
type: checkbox
props:
checked: false
indeterminate: true
label: All items
CheckboxGroup presents a related set of independent choices. It keeps spacing, disabled state, and value updates consistent while allowing any number of options to be selected.
Readiness
complete
Preview
live
Props
5
Examples
1
Code
implementation mapped
When to use
Selecting multiple notification channels, scopes, tags, or capabilities
Short option sets where all choices should remain visible
Filters where zero, one, or many values can be active
When not to use
Exactly one option must be selected; use RadioGroup or Select
Very long option lists; use searchable multi-select when available
Binary on/off settings; use Switch or Checkbox
Accessibility
Role: group
Tab — Moves through each checkbox
Space — Toggles the focused checkbox
Screen reader: Each option announces checked state and label.
Notes: Wrap with Field or a labelled group so the option set has an accessible name.
Props
Name
Type
Default
Description
value
array
—
Selected option values.
options*
array
—
Available options as value/label pairs.
direction
enum: vertical | horizontal
vertical
Visual layout direction.
disabled
boolean
false
Disables every checkbox in the group.
on_change
string
—
Examples
Notification channels
Choose notification destinations for an alert rule.
Choose a colour. Swatches are native buttons (so Enter/Space and focus come from the platform); the selected swatch shows a check overlay. A hex field accepts any value and commits on Enter or blur, with a live preview chip. When no `palette` prop is given a neutral default palette is shown. State is local and disposal-safe.
Readiness
complete
Preview
live
Props
3
Examples
2
Code
implementation mapped
When to use
Assigning an accent / brand / tag / board colour
A curated palette covers most cases, with hex as an escape hatch
The choice is a single colour value stored as a hex string
When not to use
Full colour authoring (HSL wheels, alpha, gradients) — out of scope
Picking an icon — use IconPicker
Picking from text options — use Select / Combobox
Multiple colours at once — this primitive is single-value
Accessibility
Role: listbox
Tab — Move between swatches and the hex field (native focus order)
Enter — Activate the focused swatch, or commit the hex field
Space — Activate the focused swatch
Screen reader: The swatch grid is a role=listbox labelled "Colour palette"; each swatch is a role=option button with aria-selected and an aria-label equal to its hex value, so the colour is announced by value rather than as an unlabelled box. The hex field has its own aria-label.
Notes: Colour is never the only signal — the selected swatch also shows a visible check glyph so colourblind users can tell which is active. The check meets contrast against the swatch via a dark fixed tone.
Props
Name
Type
Default
Description
value
string
—
Currently selected colour as a hex string (e.g. #22c55e).
palette
array
[]
Swatch hex values. Empty → a neutral default palette.
A single-value picker for option sets too large (or too open) for a plain Select. The user types; the list filters case-insensitively on both option label and value; Enter commits either the focused suggestion or the raw free text. The popup closes on Escape, on outside click, or after a commit. State is local and disposal-safe — no timers, no leaked closures.
Readiness
complete
Preview
live
Props
4
Examples
2
Code
implementation mapped
When to use
Option set is large enough that typing beats scrolling (countries, tags, repos)
Arbitrary free-text values are acceptable alongside suggestions
The field benefits from type-ahead narrowing as the user types
A single value is selected (use MultiSelect for many)
When not to use
The value must be exactly one of a small fixed list — use Select
Multiple values can be chosen — use MultiSelect
Picking an icon or a colour — use IconPicker / ColorPicker
Free text with no suggestions at all — use a plain Input
Accessibility
Role: combobox
ArrowDown — Open the suggestion list / move focus to the next suggestion
ArrowUp — Move focus to the previous suggestion
Enter — Commit the focused suggestion, or the typed free text if none is focused
Escape — Close the suggestion list without committing
Screen reader: The input carries role=combobox with aria-expanded reflecting the popup state and aria-autocomplete=list. The popup is a role=listbox of role=option items; the focused option is marked aria-selected so assistive tech tracks the active descendant.
Notes: Focus stays in the text input while arrowing the list (combobox pattern) so the user can keep typing. The empty state is announced via aria-disabled rather than silently rendering nothing.
Props
Name
Type
Default
Description
value
string
—
Currently committed value (an option value, or free text).
A compact binary toggle representing a filter. Click toggles the active state; the chip's visual reflects whether the filter is on. Multiple FilterChips together represent OR-style filters (typically) — the application controls the join semantic.
Readiness
complete
Preview
live
Props
4
Examples
1
Code
implementation mapped
When to use
Filter rows above lists / tables (status filter, tag filter)
Multi-faceted search with toggleable categories
Quick toggles inside Toolbar / PanelToolbar
Mobile filter sheets where chips are easier than radio groups
When not to use
Read-only labels — use Tag (when it lands)
Mutually-exclusive choice — use SegmentedControl or RadioGroup
Long-running action — use Button
Accessibility
Role: button
Enter — Toggle the filter
Space — Toggle the filter
Tab — Focus to/from the chip
Screen reader: Announces label + 'pressed' / 'not pressed' state via aria-pressed. Group of FilterChips should declare an accessible name (e.g. 'Filter by status') via the wrapping element.
Notes: Use aria-pressed for binary toggle semantics — not aria-checked (which is reserved for checkbox-like roles).
Pick one icon from the library. A search box filters the key set; the grid is a roving-focus listbox where arrow keys move the highlight and Enter/Space commits. Selection is reflected with a token-driven highlight. When no `icons` prop is supplied a small curated default set is shown. State is local and disposal-safe.
Readiness
complete
Preview
live
Props
3
Examples
2
Code
implementation mapped
When to use
Assigning an icon to a board, saved view, custom element or tag
The icon must come from the shared library (consistent rendering)
A searchable grid is friendlier than a long dropdown of icon names
When not to use
Picking a colour — use ColorPicker
Picking from arbitrary text options — use Combobox / Select
Uploading a custom image — that is a file upload, not this picker
Multiple icons at once — this primitive is single-select
Accessibility
Role: listbox
ArrowRight — Move highlight to the next icon
ArrowDown — Move highlight to the next icon
ArrowLeft — Move highlight to the previous icon
ArrowUp — Move highlight to the previous icon
Enter — Commit the highlighted icon
Space — Commit the highlighted icon
Screen reader: The grid is a role=listbox labelled "Icons"; each cell is a role=option button with aria-selected reflecting the current value and a title equal to the icon key so the glyph is announced by name rather than as an empty graphic.
Notes: Each glyph is decorative SVG; the accessible name comes from the button title (the icon key), never from the SVG itself. The empty search state renders explanatory text rather than a blank grid.
Props
Name
Type
Default
Description
value
string
—
Currently selected icon key.
icons
array
[]
Icon keys to offer. Empty → a curated default set.
disabled
boolean
false
Examples
Icon picker
Default curated icon set, single-select.
YAML
type: icon-picker
props:
icons:
- home
- settings
- user
- star
- activity
- zap
- eye
- filter
- clock
- code
- chat
- list
- grid
- globe
Disabled
Disabled state.
YAML
type: icon-picker
props:
disabled: true
icons:
- home
- settings
- star
LabeledSwitch is the settings-row version of Switch. It pairs a boolean control with a title and optional description so users understand the state before toggling it.
Readiness
complete
Preview
live
Props
5
Examples
1
Code
implementation mapped
When to use
Settings that turn a feature, rule, or notification on or off
Boolean controls that need one sentence of context
Rows where the label and switch should align as one setting
When not to use
Multiple-choice selection; use RadioGroup, RadioCardGroup, or Select
Required agreement or acknowledgement; use Checkbox
Actions that immediately run work; use Button
Accessibility
Role: switch
Space — Toggles the switch
Enter — Toggles the switch
Tab — Moves focus to and from the switch
Screen reader: Announces checked state, label, and disabled state.
Notes: Use positive labels such as Enabled or Send alerts; avoid double negatives.
Props
Name
Type
Default
Description
checked
boolean
false
Current boolean value.
label*
string
—
Visible setting title.
description
string
—
Optional helper text under the label.
disabled
boolean
false
Disables the switch.
on_change
string
—
Examples
Retry setting
Turn automatic retry behavior on for an action.
Retry failed runsAutomatically retry transient failures before alerting an operator.
YAML
type: labeled-switch
props:
checked: true
label: Retry failed runs
description: Automatically retry transient failures before alerting an operator.
Pick several values from a fixed option set. The trigger shows the selection as chips (each with an inline remove affordance) or a placeholder when empty, plus a count. The popup is a multi-selectable listbox: Space/Enter toggles the focused option, arrows move focus, Escape closes. Every toggle emits the full new selection. State is local and disposal-safe (backdrop-based outside-click, like Select).
Readiness
complete
Preview
live
Props
4
Examples
2
Code
implementation mapped
When to use
A field holds a set of values from a fixed list (roles, scopes, labels)
The user needs to see and remove current choices at a glance
Options are known up front (use Combobox for open-ended typing)
When not to use
Exactly one value — use Select
Free-text or very large/open option sets — use Combobox
A short list where all options should always be visible — use CheckboxGroup
Picking an icon or colour — use IconPicker / ColorPicker
Accessibility
Role: listbox
Enter — Open the popup (when closed) / toggle the focused option
Space — Toggle the focused option
ArrowDown — Open the popup (when closed) / move focus to the next option
ArrowUp — Move focus to the previous option
Escape — Close the popup
Screen reader: The trigger is a role=combobox with aria-haspopup=listbox and aria-expanded. The popup is a role=listbox with aria-multiselectable=true; each option carries aria-selected so assistive tech reports the toggled state. Chip remove controls carry an aria-label of "Remove".
Notes: Selected state is conveyed by a check glyph in the option box, not by colour alone, so it survives a colourblind or high-contrast environment. The chip count is aria-hidden decorative — the chips themselves carry the semantic content.
NativeSelect uses the browser and operating system's own option picker while matching the platform input chrome. It is the conservative choice when native keyboard, mobile, or assistive-technology behavior matters more than custom dropdown styling.
Readiness
complete
Preview
live
Props
5
Examples
1
Code
implementation mapped
When to use
Single-value choices in accessibility-sensitive or mobile-heavy forms
Short option sets where native option behavior is preferred
Settings panels where consistency with browser controls is desirable
When not to use
Custom option rendering, icons, or rich descriptions; use Select or a richer picker
Large searchable lists
Multiple selection
Accessibility
Role: combobox
Tab — Focuses the select
ArrowDown — Moves through native options
ArrowUp — Moves through native options
Enter — Commits selection in browsers that require confirmation
Screen reader: Uses native select semantics and browser option announcements.
Notes: Wrap with Field so the select has a visible and programmatic label.
Props
Name
Type
Default
Description
value
string
—
Selected option value.
options*
array
—
Available options as value/label pairs.
placeholder
string
Select...
Disabled placeholder option when no value is selected.
disabled
boolean
false
Disables the select.
on_change
string
—
Examples
Role select
Assign an access role using native select behavior.
A single mutually-exclusive choice within a RadioGroup. Use when the user must pick exactly one option from a small visible set. For >5 options, prefer Select (or SearchableSelect) — radios scale poorly vertically.
Readiness
complete
Preview
live
Props
6
Examples
1
Code
implementation mapped
When to use
Pick exactly one from 2–5 visible options
Inside RadioGroup (the parent component, not a bare Radio)
Settings panels where all options must be visible at once
Form steps where the choice changes the next page (Wizard)
When not to use
Bare Radio without a RadioGroup — semantics fail
Multiple selections — use CheckboxGroup
Long lists (>5) — use Select / SearchableSelect
Card-styled options with descriptions — use RadioCardGroup
Accessibility
Role: radio
ArrowUp — Move focus + selection to previous radio in the group
ArrowDown — Move focus + selection to next radio in the group
Tab — Move focus to/from the group (single tab stop)
Screen reader: Announces `checked` state and the option's label. Group is announced as `role=radiogroup`. Tab moves to/from the group; Arrow keys move inside.
Notes: Per W3C ARIA practices, a RadioGroup is a single tab stop — once focused, arrow keys move between options.
Props
Name
Type
Default
Description
checked
boolean
—
on_change
string
—
label
string
—
name
string
—
HTML name for radio-group association. Set by RadioGroup automatically.
value
string
—
Value emitted to the parent on change.
disabled
boolean
false
Examples
Plan tier
Plan tier selection.
YAML
type: stack
props:
gap: sm
children:
- type: radio
props:
name: plan
value: free
checked: ${state.plan == 'free'}
on_change: ${actions.set_plan}
label: Free
- type: radio
props:
name: plan
value: pro
checked: ${state.plan == 'pro'}
on_change: ${actions.set_plan}
label: Pro
- type: radio
props:
name: plan
value: team
checked: ${state.plan == 'team'}
on_change: ${actions.set_plan}
label: Team
RadioCardGroup presents a small set of exclusive choices where each option needs a title and supporting description. It gives the visual weight of cards while retaining radiogroup semantics.
Readiness
complete
Preview
live
Props
4
Examples
1
Code
implementation mapped
When to use
Choosing a plan, mode, density, or strategy from a short list
Exclusive choices that need explanatory copy
Setup or configuration screens where comparison matters
When not to use
Long option lists; use Select
Multiple selectable values; use CheckboxGroup
Simple one-word choices where RadioGroup is clearer and lighter
Accessibility
Role: radiogroup
Tab — Moves focus into and out of the card choices
Enter — Selects the focused card
Space — Selects the focused card
Screen reader: Each card announces role=radio and selected state.
Notes: Descriptions should distinguish options, not repeat the title.
Props
Name
Type
Default
Description
value
string
—
Selected option value.
options*
array
—
Available card options.
disabled
boolean
false
Disables every option card.
on_change
string
—
Examples
Density cards
Choose a workspace density with descriptions.
YAML
type: radio-card-group
props:
value: balanced
options:
- value: compact
title: Compact
description: More rows visible in operational panels.
- value: balanced
title: Balanced
description: Default spacing for mixed reading and action.
- value: relaxed
title: Relaxed
description: More whitespace for presentation-heavy surfaces.
A select whose dropdown contains a `<SearchInput>`, so the user type-to-filters a long option list instead of scrolling it. Supports optional grouping, a loading state (async option fetch), and a disabled state. Reach for it when a plain `<Select>` would force the user to scan dozens+ of options. It lives portal-side today (`portal/src/components/searchable_select.rs`) with this catalog entry as the stable contract.
Readiness
complete
Preview
live
Props
5
Examples
2
Code
implementation mapped
When to use
A select with more options than is comfortable to scroll (elements, circles, timezones).
Option lists fetched async — `loading` shows a spinner in the dropdown.
Grouped options where the group headers aid scanning (`show_groups`).
When not to use
A short fixed list (≤ ~7) — a plain `<Select>` / `<NativeSelect>` is simpler.
Free-text entry — use `<Input>` or a combobox that accepts arbitrary values.
Multi-select tags — that needs a token/chips input, not this single-select.
Accessibility
Role: combobox
ArrowDown — Move into the filter / to the next option.
ArrowUp — Move to the previous option.
Enter — Commit the focused selection.
Escape — Close the dropdown without changing the value.
Screen reader: `role=combobox` with the filter input as the controlling element and options as `option`/`group`. Filtering must update an `aria-live` result count so SR users know the list narrowed; the trigger must announce the current value.
Notes: `portal::components::searchable_select::SearchableSelect` is the current home. Filtering shows/hides options; it does not reorder.
Props
Name
Type
Default
Description
items
array
—
The selectable options (each may carry a description and group). Reactive. Required.
placeholder
string
Search...
Filter-input placeholder inside the dropdown.
show_groups
boolean
true
Render group headers when items carry a `group`.
loading
boolean
false
Async-fetch state — shows a spinner in the dropdown.
disabled
boolean
false
Disables the trigger.
Examples
Grouped searchable select
Element picker over a long grouped list — the canonical use.
A custom-styled single-value dropdown. Option list is rendered with consistent focus / hover / selected treatment; the trigger surface matches Input visuals so a Select sits naturally inside a Field. Use NativeSelect when OS-native keyboard / screen-reader parity matters more.
Readiness
complete
Preview
live
Props
5
Examples
1
Code
implementation mapped
When to use
Single-value selection from a known list (status, category, role)
Mid-density forms where a custom style is preferred to native chrome
Inline filter controls in toolbars and panels
Settings panels where the option set is short (<20 entries)
When not to use
Long lists (>30 entries) — use SearchableSelect for type-to-filter
Multiple values — use MultiSelect when it lands
Free-text + suggestions — use Combobox when it lands
Mobile-first surfaces where OS-native chrome is preferred — use NativeSelect
Accessibility
Role: combobox
Tab — Focus to/from the trigger
Space — Open the dropdown
Enter — Open / commit selection
ArrowDown — Move highlight to next option
ArrowUp — Move highlight to previous option
Escape — Close dropdown without committing
Screen reader: Trigger announces selected value or placeholder. Open list announces role=listbox; options announce role=option with aria-selected on the current selection.
Notes: Always wrap with `field` so the label is wired correctly. A bare `select` without a label fails the form-control audit.
Props
Name
Type
Default
Description
value
string
—
on_change
string
—
placeholder
string
Select...
disabled
boolean
false
error
boolean
false
Examples
Status select
Status dropdown bound to a signal.
YAML
type: field
props:
label: Status
field_id: status
slots:
default:
- type: select
props:
value: ${state.status}
on_change: ${actions.set_status}
placeholder: Choose status...
A binary toggle for feature-flag state ("Notifications: on/off"). Use Switch when the action is "turn on / turn off." Use Checkbox when the action is "select / deselect" (list-membership semantic). Pair with LabeledSwitch for the labelled variant.
Readiness
complete
Preview
live
Props
4
Examples
2
Code
implementation mapped
When to use
Toggling a feature on / off (notifications, dark mode, sync)
Settings rows with adjacent description (use LabeledSwitch)
State that is reflected immediately (no Save button)
Single binary preference where 'switch' reads naturally
When not to use
List-membership ('include this item') — use Checkbox
Mutually-exclusive choice — use Radio
State that needs explicit Save before applying — Switch implies immediacy
Accessibility
Role: switch
Space — Toggle the switch
Enter — Toggle the switch
Tab — Focus to/from the switch
Screen reader: Announces 'on' / 'off' (via aria-checked). Some SR pronounce role=switch as 'toggle button' — both are acceptable; the on/off semantic is preserved.
Notes: Switch state is committed instantly. If the action requires confirmation (e.g. destructive), use Checkbox + Submit instead.