Guides

Project-specific UI hints (meta)

Attach your own typed metadata to filters and options without changing the core.

Your UI often needs extra per-filter information that the library has no opinion about — a layout variant, a group, an icon, a step size. Attach it via meta. The core never reads meta; it only carries it through to filters / filterMap for your UI to branch on. Because the shapes are yours, they're fully typed — you declare them once by augmenting the library's interfaces:

// e.g. src/types/filters.d.ts
declare module '@mbsatimov/use-filters' {
  interface FilterMeta {
    variant?: 'inline' | 'stacked'; // available on EVERY filter kind
  }
  interface SelectFilterMeta {
    group?: 'primary' | 'advanced'; // only on select filters
  }
  interface NumberFilterMeta {
    unit?: string; // only on number filters, e.g. '$'
  }
  interface FilterOptionMeta {
    icon?: React.ComponentType; // on every option
  }
  interface FiltersMeta {
    layout?: 'toolbar' | 'sidebar'; // the whole set
  }
}

Now pass meta where it's relevant, checked against the shape you declared:

status: f.select({
  label: 'Status',
  valueType: 'string',
  options: [{ label: 'Open', value: 'open', meta: { icon: OpenIcon } }],
  meta: { group: 'primary' }
});

min_price: f.number({ label: 'Min price', meta: { unit: '$' } });

useFilters(configs, { meta: { layout: 'sidebar' } });

And read it back when rendering:

filters.map((filter) =>
  filter.meta.group === 'advanced' ? <AdvancedSlot filter={filter} /> : <Control filter={filter} />
);

There's a per-kind interface (SelectFilterMeta, NumberFilterMeta, …) so a hint can be specific to one kind, a shared FilterMeta for hints that apply to all, a FilterOptionMeta for options, and a FiltersMeta for the whole set.

The old FilterOption.icon / leftSlot / rightSlot, the per-filter className, and f.number / f.numberRange's unit were removed in 1.0 — rendering concerns don't belong on a headless core. Declare what you need on FilterOptionMeta / FilterMeta / NumberFilterMeta and pass it via meta instead (same data, typed by you).