Form controls
FilterChips
One choice out of many short options, every one in sight. A row of pressable chips that wraps, so a dozen categories never scroll past the edge or squeeze onto two lines. One chip is always pressed. For two to four options use a SegmentedControl, and for a long list a Select.
Filtering a list
A count beside each label shows where the bulk of the list is before anyone picks.
allWithout counts
StrapiUnder a touch screen every chip takes a 44px target and wrapped rows sit 18px apart, so a tap near the bottom of a chip never lands on the chip below. A mouse keeps the 6px gap.
Hints and errors
hint puts a line of help under the row, and error replaces it while it
is set. The group's aria-describedby points at whichever line shows. ARIA refuses aria-invalid on a group and on the buttons inside it, so the error reaches a reader through
the description alone. Use a hint for what a choice changes, and an error for a choice the form refused.
Pick WordPress below to see the error replace the hint.
The importer maps each source's types to schema fields.
id names the group, and the hint and the error take their ids from it. Left out, the group
carries no id and the messages take a generated one. A row given none of these props looks and reads
as it did before 0.38.0. A row of links takes the same props.
Since 0.38.0 every row takes a number from Svelte's id counter, even with none of these props set. A generated id rendered after a FilterChips or a SegmentedControl on the same page is therefore renumbered. Only a snapshot test that records those ids notices.
Inside a Field
Field draws the caption and its own message. Give it group, because a label's for never reaches a group of chips, and pass
the wiring it hands over as id and describedBy. The Field's message is
then read with the row. A row inside a Field takes no hint or error of its own, because it names
its message from the same id as the Field and a reader would then hear one of the two twice.
FilterChips takes no labeledBy, and its label names the group without being
drawn. Give that label the caption's words, so a reader hears the name a sighted user sees and nothing
shows twice.
The importer reads one source per run.
A filter kept in the URL
Give every chip an href and the row renders links instead of buttons. The current
chip is still the one whose value matches value, and it carries aria-current="page". A link chip reports no change, so onchange never fires.
The page the link opens reads the filter from its URL instead.
The chips are plain links, so they work before the page hydrates. A server-rendered list filters
with no script at all, a reload keeps the filter, and the back button returns to the last one.
Every chip carries an href or none does. A row that mixes the two throws, because a button
beside two links would report a choice the URL never learns about.
?status=allIn SvelteKit, data-sveltekit-noscroll and data-sveltekit-keepfocus on a
wrapper keep the reader's scroll position and focus when a chip is chosen. SegmentedControl takes an href per option
the same way, for a filter of two to four options.
Accessibility
The row is a group named by label. Each chip is a button whose aria-pressed says whether it is the one chosen. In a row of links each chip is a
link, and the current one carries aria-current="page". countLabel is read
after each count, so "3" is heard as "3 on sale".
API
| Prop | Type | Default | Description |
|---|---|---|---|
value required | T | no default | Bindable. The pressed chip's value, of the options' value type T. In a row of links, the current chip's value. |
options required | FilterChip<T>[] | no default | The chips, in order. |
label required | string | no default | The group's accessible name. |
countLabel | string | '' | Read after each count by assistive technology. |
id | string | no default | The group's id. The hint and the error take theirs from it. One is generated for the messages when left out. |
hint | string | no default | Shown under the row while there is no error. |
error | string | no default | Replaces the hint while it is set. The group points at it and is not marked invalid, because ARIA refuses that attribute on a group. |
describedBy | string | no default | Ids of other elements that describe the group, separated by spaces, such as a wrapping Field's message. Read after the row's own hint or error. |
class | string | no default | Extra classes on the row. |
onchange | (value: T) => void | no default | Fires when a different chip is pressed. A row of links never fires it. |
noAI | boolean | false | Keep the value from an assistant: a FormAssist never reports it or fills it, and the control is marked data-no-ai for a browser agent. |
name | string | no default | Posts the chosen value with the surrounding form, through a hidden input. |
FilterChip
| Prop | Type | Default | Description |
|---|---|---|---|
value required | string | no default | The chosen value, and the key the chip renders under. |
label required | string | no default | What the reader sees. |
count | number | no default | How many rows the chip leaves on screen. |
icon | Component | no default | A lucide component before the label. |
href | string | no default | Renders the chip as a link to this URL instead of a button. Every chip carries one or none does. |