KQ-1315 · FILTER/BUILDER
Filter Builder
A query builder over typed rows: rules of field, condition and value in nested All / Any groups, each with a rail down its left edge. Switching a group slides its thumb on snap, re-colours the rail and rolls every and between its rows to or on snap a cascade apart, so the change runs down the group; rules arrive from zero height on glide and leave on the exit ease while the gap closes on glide. Every change re-runs the query and the count rolls to its new figure a digit at a time on snap, chips above summarise the query and lead back to their rows, and the controls are native selects and inputs in groups and radio groups.
Transactions
5 rules · 2 groups
151of 2,400 transactions
151 of 2,400 transactions · 5 rules · 2 groups
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/filter-builder
Props
- nesting
- number
- default 2
- How deep groups may nest, 0 to 3. At 0 the query is a flat list of rules with no Add group and no inner rails.
- chips
- boolean
- default true
- A strip of chips above the builder summarising each top-level rule or group; a chip focuses its row and its × removes it.
- count
- "rows" | "share" | "off"
- default "rows"
- The result readout: a rolling row count, the share with a meter that glides to it, or none.
- value / defaultValue
- FilterGroup
- default defaultFilterQuery
- The query: a root group of rules and nested groups. Controlled or uncontrolled.
- onValueChange
- (query: FilterGroup) => void
- default —
- Fires from the control that changed the query, with the whole new query.
- fields
- FilterField[]
- default defaultFilterFields
- What can be filtered on: id, label, type (text, number, enum, date, boolean), enum options, number prefix and suffix.
- rows
- FilterRow[]
- default defaultFilterRows
- The records the count and preview are taken over. The default is 2,400 seeded transactions.
- matches
- number
- default —
- A count from your server; overrides counting rows.
- total
- number
- default —
- The total from your server. Defaults to rows.length.
- now
- number | Date
- default defaultFilterNow
- Where "in the last N days" counts back from.
- onApply
- (query: FilterGroup) => void
- default —
- The footer's Show button, and Enter in a value. Without it there is no Show button.
- applyLabel
- string
- default "Show"
- The Show button's verb; the count follows it.
- maxRules
- number
- default 12
- Rules allowed in the whole query; the Add buttons disable at the limit.
- noun
- { one: string; other: string }
- default { one: "row", other: "rows" }
- What a row is called in the count and its announcement.
- formatCount
- (n: number) => string
- default —
- Counts as text. Defaults to grouped digits in en-US, so the server and the browser print the same.
- renderRow
- (row: FilterRow) => ReactNode
- default —
- One row of the desktop preview. Defaults to the first text field, a few others as meta, and the first number on the right.
- status
- "ready" | "loading" | "error"
- default "ready"
- Whether the count has arrived, for a server count: Counting… while loading, Count unavailable with Try again on error.
- onRetry
- () => void
- default —
- Try again was pressed while status is "error".
- title
- string
- default "Filters"
- The builder's heading; also its accessible name unless label is given.
- label
- string
- default —
- The builder's accessible name. Defaults to the title.
- sound
- boolean
- default false
- A click for each field, condition or match change, a pop for each rule or group added and a lower one for each removed. Typing is silent.
- disabled
- boolean
- default false
- Read only: the query shows and nothing changes.
- className
- string
- default —
- Classes for the root. It is at most 560px tall and its body scrolls between a fixed header and footer.
| Prop | Type | Default | Description |
|---|---|---|---|
| nesting | number | 2 | How deep groups may nest, 0 to 3. At 0 the query is a flat list of rules with no Add group and no inner rails. |
| chips | boolean | true | A strip of chips above the builder summarising each top-level rule or group; a chip focuses its row and its × removes it. |
| count | "rows" | "share" | "off" | "rows" | The result readout: a rolling row count, the share with a meter that glides to it, or none. |
| value / defaultValue | FilterGroup | defaultFilterQuery | The query: a root group of rules and nested groups. Controlled or uncontrolled. |
| onValueChange | (query: FilterGroup) => void | — | Fires from the control that changed the query, with the whole new query. |
| fields | FilterField[] | defaultFilterFields | What can be filtered on: id, label, type (text, number, enum, date, boolean), enum options, number prefix and suffix. |
| rows | FilterRow[] | defaultFilterRows | The records the count and preview are taken over. The default is 2,400 seeded transactions. |
| matches | number | — | A count from your server; overrides counting rows. |
| total | number | — | The total from your server. Defaults to rows.length. |
| now | number | Date | defaultFilterNow | Where "in the last N days" counts back from. |
| onApply | (query: FilterGroup) => void | — | The footer's Show button, and Enter in a value. Without it there is no Show button. |
| applyLabel | string | "Show" | The Show button's verb; the count follows it. |
| maxRules | number | 12 | Rules allowed in the whole query; the Add buttons disable at the limit. |
| noun | { one: string; other: string } | { one: "row", other: "rows" } | What a row is called in the count and its announcement. |
| formatCount | (n: number) => string | — | Counts as text. Defaults to grouped digits in en-US, so the server and the browser print the same. |
| renderRow | (row: FilterRow) => ReactNode | — | One row of the desktop preview. Defaults to the first text field, a few others as meta, and the first number on the right. |
| status | "ready" | "loading" | "error" | "ready" | Whether the count has arrived, for a server count: Counting… while loading, Count unavailable with Try again on error. |
| onRetry | () => void | — | Try again was pressed while status is "error". |
| title | string | "Filters" | The builder's heading; also its accessible name unless label is given. |
| label | string | — | The builder's accessible name. Defaults to the title. |
| sound | boolean | false | A click for each field, condition or match change, a pop for each rule or group added and a lower one for each removed. Typing is silent. |
| disabled | boolean | false | Read only: the query shows and nothing changes. |
| className | string | — | Classes for the root. It is at most 560px tall and its body scrolls between a fixed header and footer. |