# Filter records

Build collection filters on your collection's schema, query and permissions.

Import: @slices.sh/collection/headless

Public parts: 39

## Installation

### 1. Install the service registry

services/index.ts, which `import "@/services"` loads. A provider setup writes the same file; skip this if your app has one.

```bash
npx shadcn@latest add "https://slices.sh/r/services.json"
```

### 2. Install the headless library

```bash
npm install @slices.sh/collection@^0.1.6
```

### 3. Install the service

Install the provider configuration via shadcn or the slices CLI. Skip this step if your app already has the service configured. Provider commands and provisioning: https://slices.sh/docs/services/collection.md

## Anatomy

### Composition

```text
Collection.Root
  Collection.FilterBar
    Collection.FilterSheet
    Collection.FieldMenu
      Collection.FieldList
        Collection.FieldOption
      Collection.FieldSearch
    Collection.AddFilter
    Collection.FilterPill
      Collection.EditorPopover
        Collection.FilterEditor control="enum"
          Collection.OptionSearch
          Collection.SelectAllOptions
          Collection.ClearOptions
          Collection.OptionItem
        Collection.FilterEditor control="boolean"
          Collection.BooleanChoice
        Collection.FilterEditor control="text"
          Collection.TextOperator
          Collection.TextValue
        Collection.FilterEditor control="range"
          Collection.RangeMin
          Collection.RangeMax
          Collection.RangeUnit
          Collection.RangeSlider
          Collection.RangeBucket
        Collection.FilterEditor control="date"
          Collection.DatePreset
          Collection.DateCustom
          Collection.DateFrom
          Collection.DateTo
          Collection.DateCalendar
          Collection.DateText
      Collection.PillField
      Collection.PillValue
      Collection.RemoveFilter
      Collection.PillOperator
    Collection.ClearFilters
    Collection.RemoveLastFilter
    Collection.FilterCount
    Collection.QuickFilter
    Collection.ResultCount
    Collection.Filter field="status"
      Collection.Option
```

## Minimal composition

```tsx
"use client"

import "@/services"
import { Collection } from "@slices.sh/collection/headless"
import type { CollectionSchema } from "@slices.sh/collection/services/types"

export function Example({ schema }: { schema: CollectionSchema }) {
  return (
    <Collection.Root collection={schema.collection} schema={schema}>
      <Collection.Search aria-label="Search records" />
      <Collection.FilterBar>
        <Collection.AddFilter>Add filter</Collection.AddFilter>
        <Collection.FilterPill>
          <Collection.PillField />
          <Collection.PillValue />
          <Collection.RemoveFilter>Remove</Collection.RemoveFilter>
        </Collection.FilterPill>
      </Collection.FilterBar>
      <Collection.ClearFilters>Clear filters</Collection.ClearFilters>
      <Collection.Row render={<div />}>
        <Collection.Cell render={<span />}>
          <Collection.Value />
        </Collection.Cell>
      </Collection.Row>
    </Collection.Root>
  )
}

```

Supply a registered collection schema. Parts use its fields, permissions and provider capabilities.

## Complete API reference

### Collection.FilterBar

content

The bar that holds the filters, the searchable field picker (a popover where there is room, a sheet on a phone) and the count of filters that are on.

Import: @slices.sh/collection/headless

Capability: filters

Collection.FilterBar needs Root.

```tsx
PartProps<null, { count: number }>
```

Source: @slices.sh/collection/src/headless/filter-bar.tsx

### Collection.AddFilter

action · Element: button

The bar that holds the filters, the searchable field picker (a popover where there is room, a sheet on a phone) and the count of filters that are on.

Import: @slices.sh/collection/headless

Capability: filters

Collection.AddFilter needs Root.

```tsx
PartProps<"button", { count: number; open: boolean }>
```

Source: @slices.sh/collection/src/headless/add-filter.tsx

### Collection.FilterPill

content · Element: div

One pill per clause, with its field, operator, value summary and removal; clearing, the empty-state remedy, declared quick presets and the live result count. ResultCount is mounted before it has a number, and its count stays null when the provider did not count.

Import: @slices.sh/collection/headless

Capability: filters

Collection.FilterPill needs Root.

Collection.Pill needs FilterPill.

Collection.Pill needs Root.

```tsx
PillProps

type PillProps = PartProps<"div", { clause: FilterClause; editing: boolean }>
```

Source: @slices.sh/collection/src/headless/filter-pill.tsx

### Collection.PillField

content · Element: span

One pill per clause, with its field, operator, value summary and removal; clearing, the empty-state remedy, declared quick presets and the live result count. ResultCount is mounted before it has a number, and its count stays null when the provider did not count.

Import: @slices.sh/collection/headless

Capability: filters

Collection.PillField needs FilterPill.

```tsx
PartProps<"span">
```

Source: @slices.sh/collection/src/headless/pill-field.tsx

### Collection.PillOperator

action · Element: button

One pill per clause, with its field, operator, value summary and removal; clearing, the empty-state remedy, declared quick presets and the live result count. ResultCount is mounted before it has a number, and its count stays null when the provider did not count.

Import: @slices.sh/collection/headless

Capability: filters

Collection.PillOperator needs FilterPill.

Collection.PillOperator needs Root.

```tsx
PartProps<"button", { operator: FilterOperator; operators: readonly FilterOperator[] }>
```

Source: @slices.sh/collection/src/headless/pill-operator.tsx

### Collection.PillValue

action · Element: button

One pill per clause, with its field, operator, value summary and removal; clearing, the empty-state remedy, declared quick presets and the live result count. ResultCount is mounted before it has a number, and its count stays null when the provider did not count.

Import: @slices.sh/collection/headless

Capability: filters

Collection.PillValue needs FilterPill.

Collection.PillValue needs Root.

```tsx
PartProps<"button", { summary: string }>
```

Source: @slices.sh/collection/src/headless/pill-value.tsx

### Collection.RemoveFilter

action · Element: button

One pill per clause, with its field, operator, value summary and removal; clearing, the empty-state remedy, declared quick presets and the live result count. ResultCount is mounted before it has a number, and its count stays null when the provider did not count.

Import: @slices.sh/collection/headless

Capability: filters

Collection.RemoveFilter needs FilterPill.

Collection.RemoveFilter needs Root.

```tsx
PartProps<"button">
```

Source: @slices.sh/collection/src/headless/remove-filter.tsx

### Collection.FilterCount

content · Element: span

The bar that holds the filters, the searchable field picker (a popover where there is room, a sheet on a phone) and the count of filters that are on.

Import: @slices.sh/collection/headless

Capability: filters

Collection.FilterCount needs Root.

```tsx
PartProps<"span", { count: number }>
```

Source: @slices.sh/collection/src/headless/filter-count.tsx

### Collection.ClearFilters

action · Element: button

One pill per clause, with its field, operator, value summary and removal; clearing, the empty-state remedy, declared quick presets and the live result count. ResultCount is mounted before it has a number, and its count stays null when the provider did not count.

Import: @slices.sh/collection/headless

Capability: filters

Collection.ClearFilters needs Root.

```tsx
PartProps<"button", { count: number }>
```

Source: @slices.sh/collection/src/headless/clear-filters.tsx

### Collection.RemoveLastFilter

action · Element: button

One pill per clause, with its field, operator, value summary and removal; clearing, the empty-state remedy, declared quick presets and the live result count. ResultCount is mounted before it has a number, and its count stays null when the provider did not count.

Import: @slices.sh/collection/headless

Capability: filters

Collection.RemoveLastFilter needs Root.

```tsx
PartProps<"button">
```

Source: @slices.sh/collection/src/headless/remove-last-filter.tsx

### Collection.QuickFilter

action · Element: button

One pill per clause, with its field, operator, value summary and removal; clearing, the empty-state remedy, declared quick presets and the live result count. ResultCount is mounted before it has a number, and its count stays null when the provider did not count.

Import: @slices.sh/collection/headless

Capability: filters

Collection.QuickFilter needs Root.

```tsx
QuickProps

type QuickProps = PartProps<"button", { label: string; active: boolean }>
```

Source: @slices.sh/collection/src/headless/quick-filter.tsx

### Collection.ResultCount

content · Element: span

How many rows the query matched, said out loud.

Here from the first render, before there is a number to say. An `aria-live` region only
announces what arrives after it is mounted, so one that appears together with its first
count announces nothing — which is the whole of what this part is for. Empty until the
count is known.

`null` while it is unknown rather than nought: a page still in flight has no total, and "0
results" is a different claim from "not counted yet".

Import: @slices.sh/collection/headless

Capability: filters

Collection.ResultCount needs Root.

```tsx
PartProps<"span", { count: number | null }>
```

Source: @slices.sh/collection/src/headless/result-count.tsx

### Collection.FieldMenu

content · Element: div

The bar that holds the filters, the searchable field picker (a popover where there is room, a sheet on a phone) and the count of filters that are on.

Import: @slices.sh/collection/headless

Capability: filters

Collection.FieldMenu needs Root.

```tsx
PartProps<"div">
```

Source: @slices.sh/collection/src/headless/field-menu.tsx

### Collection.FieldSearch

input · Element: input

The bar that holds the filters, the searchable field picker (a popover where there is room, a sheet on a phone) and the count of filters that are on.

Import: @slices.sh/collection/headless

Capability: filters

Collection.FieldSearch needs Root.

```tsx
PartProps<"input">
```

Source: @slices.sh/collection/src/headless/field-search.tsx

### Collection.FieldList

content · Element: div

The bar that holds the filters, the searchable field picker (a popover where there is room, a sheet on a phone) and the count of filters that are on.

Import: @slices.sh/collection/headless

Capability: filters

Collection.FieldList needs Root.

```tsx
PartProps<"div">
```

Source: @slices.sh/collection/src/headless/field-list.tsx

### Collection.FieldOption

action · Element: button

The bar that holds the filters, the searchable field picker (a popover where there is room, a sheet on a phone) and the count of filters that are on.

Import: @slices.sh/collection/headless

Capability: filters

Collection.FieldOption needs Root.

```tsx
FieldOptionProps

type FieldOptionProps = PartProps<"button", { field: SchemaField; type: string; pinned: boolean }>
```

Source: @slices.sh/collection/src/headless/field-option.tsx

### Collection.EditorPopover

content · Element: div

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

Collection.EditorPopover needs Root.

Collection.EditorPopover needs FilterPill.

```tsx
PartProps<"div">
```

Source: @slices.sh/collection/src/headless/editor-popover.tsx

### Collection.FilterEditor

content

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

Collection.FilterEditor needs FilterPill.

Collection.FilterEditor needs Root.

```tsx
PartProps<null> & { control: FilterControl }
```

Source: @slices.sh/collection/src/headless/filter-editor.tsx

### Collection.OptionSearch

input · Element: input

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

Collection.OptionSearch needs FilterPill.

```tsx
PartProps<"input">
```

Source: @slices.sh/collection/src/headless/option-search.tsx

### Collection.SelectAllOptions

action · Element: button

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

Collection.SelectAllOptions needs FilterPill.

Collection.SelectAllOptions needs Root.

```tsx
PartProps<"button">
```

Source: @slices.sh/collection/src/headless/select-all-options.tsx

### Collection.ClearOptions

action · Element: button

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

Collection.ClearOptions needs FilterPill.

Collection.ClearOptions needs Root.

```tsx
PartProps<"button">
```

Source: @slices.sh/collection/src/headless/clear-options.tsx

### Collection.OptionItem

action · Element: button

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

Collection.OptionItem needs FilterPill.

Collection.OptionItem needs Root.

```tsx
OptionProps

type OptionProps = PartProps<
  "button",
  { value: string; label: string; count: number | null; selected: boolean }
>
```

Source: @slices.sh/collection/src/headless/option-item.tsx

### Collection.FilterSheet

content · Element: div

The bar that holds the filters, the searchable field picker (a popover where there is room, a sheet on a phone) and the count of filters that are on.

Import: @slices.sh/collection/headless

Capability: filters

FilterSheet needs Collection.Root.

```tsx
PartProps<"div">
```

Source: @slices.sh/collection/src/headless/filter-sheet.tsx

### Collection.TextOperator

input · Element: select

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

Collection.TextOperator needs FilterPill.

Collection.TextOperator needs Root.

```tsx
OperatorProps

type OperatorProps = PartProps<
  "select",
  { operator: FilterOperator; operators: readonly FilterOperator[] }
>
```

Source: @slices.sh/collection/src/headless/text-operator.tsx

### Collection.TextValue

input · Element: input

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

Collection.TextValue needs FilterPill.

Collection.TextValue needs Root.

```tsx
PartProps<"input">
```

Source: @slices.sh/collection/src/headless/text-value.tsx

### Collection.BooleanChoice

action · Element: button

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

Collection.BooleanChoice needs FilterPill.

Collection.BooleanChoice needs Root.

```tsx
BooleanProps

type BooleanProps = PartProps<"button", { value: boolean; selected: boolean }>
```

Source: @slices.sh/collection/src/headless/boolean-choice.tsx

### Collection.RangeMin

input · Element: input

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

Collection.Range needs FilterPill.

Collection.Range needs Root.

```tsx
BoundProps

type BoundProps = PartProps<"input", { unit?: string; min?: number; max?: number; step?: number }>
```

Source: @slices.sh/collection/src/headless/range-min.tsx

### Collection.RangeMax

input · Element: input

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

Collection.Range needs FilterPill.

Collection.Range needs Root.

```tsx
BoundProps

type BoundProps = PartProps<"input", { unit?: string; min?: number; max?: number; step?: number }>
```

Source: @slices.sh/collection/src/headless/range-max.tsx

### Collection.RangeUnit

content · Element: span

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

RangeUnit needs FilterPill.

RangeUnit needs Collection.Root.

```tsx
PartProps<"span", { unit: string }>
```

Source: @slices.sh/collection/src/headless/range-unit.tsx

### Collection.RangeSlider

content · Element: div

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

Collection.RangeSlider needs FilterPill.

Collection.RangeSlider needs Root.

```tsx
PartProps<"div">
```

Source: @slices.sh/collection/src/headless/range-slider.tsx

### Collection.RangeBucket

action · Element: button

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

Collection.RangeBucket needs FilterPill.

Collection.RangeBucket needs Root.

```tsx
PresetProps

type PresetProps = PartProps<"button", { label: string; active: boolean }>
```

Source: @slices.sh/collection/src/headless/range-bucket.tsx

### Collection.DatePreset

action · Element: button

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

Collection.DatePreset needs FilterPill.

Collection.DatePreset needs Root.

```tsx
PresetProps

type PresetProps = PartProps<"button", { name: string; label: string; hint: string; active: boolean }>
```

Source: @slices.sh/collection/src/headless/date-preset.tsx

### Collection.DateCustom

action · Element: button

The way to a range no preset names: pressed while the range is one, it takes you to the start date.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

Collection.DateCustom needs FilterPill.

Collection.DateCustom needs Root.

```tsx
PartProps<"button", { active: boolean }>
```

Source: @slices.sh/collection/src/headless/date-custom.tsx

### Collection.DateFrom

input · Element: input

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

```tsx
PartProps<"input", DateBoundState>
```

Source: @slices.sh/collection/src/headless/date-from.tsx

### Collection.DateTo

input · Element: input

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

```tsx
PartProps<"input", DateBoundState>
```

Source: @slices.sh/collection/src/headless/date-to.tsx

### Collection.DateCalendar

content · Element: div

The typed editor of the pill being edited: multi-select options with scoped counts, a boolean choice, text operators and value, numeric bounds with a slider and buckets, and a date editor with presets, typed dates and a calendar. Option counts are null where the provider has no facet counts.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

Collection.DateCalendar needs FilterPill.

Collection.DateCalendar needs Root.

```tsx
PartProps<"div">
```

Source: @slices.sh/collection/src/headless/date-calendar.tsx

### Collection.DateText

content · Element: span

The days the clause covers, in words, kept up to date as the range is picked or typed.

Import: @slices.sh/collection/headless

Capability: filters (OptionItem counts: facets)

Collection.DateText needs FilterPill.

```tsx
PartProps<"span", { summary: string }>
```

Source: @slices.sh/collection/src/headless/date-text.tsx

### Collection.Filter

input · Element: select

A native select per filterable enum field, and its options.

Import: @slices.sh/collection/headless

Capability: filters

Collection.Filter must be inside <Collection.Root>.

```tsx
FilterProps

type FilterProps = PartProps<"select", { field: SchemaField }> & {
  field?: string
}
```

Source: @slices.sh/collection/src/headless/enum-filter.tsx

### Collection.Option

content · Element: option

A native select per filterable enum field, and its options.

Import: @slices.sh/collection/headless

Capability: filters

Collection.Option must be inside <Collection.Filter> or <Collection.Create.Select>.

```tsx
OptionProps

type OptionProps = PartProps<"option", { option: string }>
```

Source: @slices.sh/collection/src/headless/option.tsx

### Collection.Root

scope

The root, and the parts that choose what is drawn under it: one of several views, the data a view needs, and one of two screens by width.

Import: @slices.sh/collection/headless

```tsx
CollectionRootProps

type CollectionRootProps = RootProps &
  CollectionViewOptions &
  CardSizeOptions &
  SavedViewOptions &
  GroupingOptions & {
    /**
     * Left out or `true`: required, and a missing service throws. `"optional"`: renders its
     * children with no rows, and every part inside renders nothing. `false`: off. A capability
     * name (`"live"`) requires the service and that capability.
     */
    enabled?: Enabled
    /** The collection config, `"default"` when left out. `collection` names one inside it. */
    config?: string
    groupSumFields?: readonly string[]
    cardSizing?: boolean
    lanes?: boolean
    collection: string
    schema: CollectionSchema
    density?: DensityValue
    onDensityChange?: (density: DensityValue) => void
    palette?: boolean
    pageSize?: number
    infinite?: boolean
    live?: boolean
    /** Whether the search, the sort and the filter travel in the address bar. */
    urlState?: boolean
    /** `false` when nothing on screen searches: no search applies, from the address or a saved view. */
    search?: boolean
    /** `false` when nothing on screen filters: no filter applies, from the address or a saved view. */
    filters?: boolean
  }
```

Source: @slices.sh/collection/src/headless/root.tsx
