KQ-1129 · SIFT/FILTER
Sift Filter
A filter field over a two-column set of cards: as you type, every card that stops matching drops off the bottom under constant acceleration with a slight spin, while the matches close ranks on the glide spring, and the set's floor waits for the last faller to pass through it before it glides up to fit. Deleting back or clearing brings the fallen up from below the floor on the snap spring, their spin unwinding, in a stagger that stays inside the choreography budget. The field is a real input: Escape clears it with the same rise as deleting, fallen cards leave the tab order and the accessibility tree at once, and IME composition filters on what was committed.
fernworks nursery · all 10 plants
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/sift-filter
Props
- items
- { id: string; title: string; meta?: string; tags?: readonly string[] }[]
- default —
- The cards: a title and a short second line, both searched and lit; tags only searched.
- label
- string
- default —
- What the field filters: its visible label and accessible name.
- placeholder
- string
- default "Type to filter"
- The input's placeholder.
- value / defaultValue
- string
- default ""
- The query. Controlled or uncontrolled.
- onValueChange
- (query: string) => void
- default —
- Fires with the new query on every edit, and with "" when cleared.
- filter
- (item: SiftFilterItem, query: string) => boolean
- default —
- Whether a card answers a query. Defaults to every word of the query appearing in its title, meta or tags.
- onSelect
- (item: SiftFilterItem) => void
- default —
- Makes each card a button, and fires with the card pressed.
- gravity
- number
- default 2750
- How hard cards fall, in px/s², 1000 to 6000: a fall of d px takes √(2d/g). Also how hard the fallen are thrown back up.
- spin
- number
- default 14
- How far a card turns on its way down, in degrees, 0 to 40. Each card falls its own way, the same way every time.
- stagger
- number
- default 35
- The gap between one card leaving (or returning) and the next, in ms, 0 to 100, tightened so a whole cascade stays within 600ms.
- highlight
- boolean
- default true
- Light the query's words in each card's title and meta.
- sound
- boolean
- default false
- Play a patter, a soft plip as each card passes through the floor (pitched per card, panned by column), and a rise when an edit brings cards back. Nothing plays, and no audio context exists, unless this is on.
- disabled
- boolean
- default false
- Disables the field and the clear button, and makes cards plain.
- className
- string
- default —
- Merged onto the root's classes.
| Prop | Type | Default | Description |
|---|---|---|---|
| items | { id: string; title: string; meta?: string; tags?: readonly string[] }[] | — | The cards: a title and a short second line, both searched and lit; tags only searched. |
| label | string | — | What the field filters: its visible label and accessible name. |
| placeholder | string | "Type to filter" | The input's placeholder. |
| value / defaultValue | string | "" | The query. Controlled or uncontrolled. |
| onValueChange | (query: string) => void | — | Fires with the new query on every edit, and with "" when cleared. |
| filter | (item: SiftFilterItem, query: string) => boolean | — | Whether a card answers a query. Defaults to every word of the query appearing in its title, meta or tags. |
| onSelect | (item: SiftFilterItem) => void | — | Makes each card a button, and fires with the card pressed. |
| gravity | number | 2750 | How hard cards fall, in px/s², 1000 to 6000: a fall of d px takes √(2d/g). Also how hard the fallen are thrown back up. |
| spin | number | 14 | How far a card turns on its way down, in degrees, 0 to 40. Each card falls its own way, the same way every time. |
| stagger | number | 35 | The gap between one card leaving (or returning) and the next, in ms, 0 to 100, tightened so a whole cascade stays within 600ms. |
| highlight | boolean | true | Light the query's words in each card's title and meta. |
| sound | boolean | false | Play a patter, a soft plip as each card passes through the floor (pitched per card, panned by column), and a rise when an edit brings cards back. Nothing plays, and no audio context exists, unless this is on. |
| disabled | boolean | false | Disables the field and the clear button, and makes cards plain. |
| className | string | — | Merged onto the root's classes. |