All exports from react-native-quick-filter. See USAGE.md for guides.
Owns the filter state and exposes it via context. Wrap the filter UI with it.
| Prop | Type | Default | Description |
|---|---|---|---|
facets |
Facet[] |
— (required) | All filter dimensions. |
chips |
ChipSpec[] |
[] |
Chips for the bar. |
selection |
Selection |
— | Controlled committed selection. |
defaultSelection |
Selection |
empty | Uncontrolled initial selection. |
onSelectionChange |
(next: Selection) => void |
— | Called on every commit/instant change (pruned selection). |
resolveResultCount |
(sel: Selection) => number | Promise<number> |
— | Live result count resolver (debounced). |
applyMode |
'instant' | 'deferred' |
per-kind | Provider-level apply mode default. |
defaultSide |
'left' | 'right' |
'right' |
Initial side stored in panel state. |
resultCountDebounceMs |
number |
250 |
Debounce before calling resolveResultCount. |
children |
ReactNode |
— |
All hooks must be used inside a <FilterProvider>.
Top-level state + global actions.
{
selection: Selection; // committed
activeCount: number; // number of active facets
isFacetActive: (facetId: string) => boolean;
facetCount: (facetId: string) => number;
resultCount: ResultCountState; // { count, status }
openDropdownFacetId: string | null;
panelOpen: boolean;
panelSide: PanelSide;
openDropdown: (facetId: string) => void;
closeDropdown: () => void;
openPanel: (side?: PanelSide) => void;
closePanel: () => void;
setPanelGroup: (facetId: string | null) => void;
commitAll: () => void;
clearAll: () => void;
removeFacet: (facetId: string) => void;
}Read/write surface for a single facet — the consumption point for panel bodies.
{
facet: Facet;
applyMode: ApplyMode;
isOpen: boolean; // open in a dropdown/panel
optionValue: string[]; // effective value (draft when open, else committed)
rangeValue: RangeValue;
count: number; // selection count for this facet
isOptionSelected: (optionId: string) => boolean;
toggleOption: (optionId: string) => void;
setOptions: (optionIds: string[]) => void;
setRange: (range: RangeValue) => void;
selectAll: () => void;
clearFacet: () => void;
commit: () => void; // deferred → commit this facet
searchQuery: string;
setSearchQuery: (q: string) => void;
visibleOptions: FacetOption[]; // filtered by searchQuery
}{ count: number | null; status: 'idle' | 'loading' | 'ready' }{
openFacetId: string | null;
isOpen: (facetId?: string) => boolean;
open: (facetId: string) => void;
close: () => void;
}{
isOpen: boolean;
side: PanelSide;
activeGroupId: string | null;
open: (side?: PanelSide) => void;
close: () => void;
setGroup: (facetId: string | null) => void;
commitAll: () => void;
}Derived state + interaction for a single chip.
{
label: string; kind: ChipKind; active: boolean; open: boolean;
count: number; badge: number; removable: boolean; leadingIcon?: ReactNode;
onPress: () => void; onRemove: () => void;
}| Prop | Type | Default |
|---|---|---|
chips |
ChipSpec[] |
provider chips |
renderChip |
(spec, index) => ReactNode |
built-in |
pinActiveFirst |
boolean |
false |
style / contentContainerStyle |
StyleProp<ViewStyle> |
— |
| Prop | Type | Default |
|---|---|---|
topOffset |
number |
0 |
dimBackdrop |
boolean |
false |
panelStyle |
StyleProp<ViewStyle> |
— |
| Prop | Type | Default |
|---|---|---|
variant |
'drilldown' | 'masterDetail' |
'drilldown' |
side |
'left' | 'right' |
'right' |
title |
string |
i18n filter |
groups |
string[] |
all facets |
width |
number |
min(380, 86% screen) |
swipeToClose |
boolean |
true |
enableBackdropDismiss |
boolean |
true |
animated |
boolean |
true |
topInset / bottomInset |
number |
0 |
footer |
(ctx: { commitAndClose }) => ReactNode |
ResultCountButton |
| Prop | Type | Default |
|---|---|---|
presentation |
'sheet' | 'fullScreen' |
'sheet' |
title |
string |
i18n filter |
groups |
string[] |
all facets |
sectionMaxHeight |
number |
280 (0 = unlimited) |
topInset / bottomInset |
number |
0 |
footer |
(ctx: { commitAndClose }) => ReactNode |
ResultCountButton |
<QuickFilterChip spec testID? />— kind-aware chip (used by the bar).<Chip label active? open? leadingIcon? trailing? onRemove? onPress? testID? />— presentational shell.<SidePanelMasterList groups onSelect />,<SidePanelRail groups activeId onSelect width? />.- Bodies:
<FacetBody facetId />,<CheckboxListBody facetId />,<RadioListBody facetId />,<RangeBody facetId />. - Atoms:
<ResultCountButton onPress? template? style? />,<FilterFooter onClear? clearLabel? children? />,<Button label onPress? variant? disabled? style? />,<Checkbox checked />,<Radio selected />,<Badge count />,<SearchInput value onChangeText placeholder? />,<Chevron open? color? size? />.
<ThemeProvider scheme? theme? override? />—scheme: 'light' | 'dark',theme: QuickFilterTheme(overrides scheme),override: { colors?, radius?, spacing?, chipActiveStyle? }.useTheme(): QuickFilterTheme— defaults to light when no provider.defaultLightTheme,defaultDarkTheme: QuickFilterTheme.mergeTheme(base, override): QuickFilterTheme.
<StringsProvider strings? />— partial dictionary; missing keys fall back to English.useStrings(): QuickFilterStrings— defaults to English when no provider.en,tr: QuickFilterStrings— built-in dictionaries.formatNumber(n): string— Turkish-grouped number (tr-TR).
type FacetKind = 'single' | 'multi' | 'range' | 'toggle';
type Presentation = 'dropdown' | 'sidePanel';
type ApplyMode = 'instant' | 'deferred';
type PanelSide = 'left' | 'right';
type ChipKind = 'action' | 'dropdown' | 'toggle' | 'segment';
type ChipBadge = 'activeCount' | 'facetCount' | 'none';
type ColorScheme = 'light' | 'dark';
type ChipActiveStyle = 'fill' | 'outline';
type SidePanelVariant = 'drilldown' | 'masterDetail';
type FilterSheetPresentation = 'sheet' | 'fullScreen';
type ResultCountStatus = 'idle' | 'loading' | 'ready';
type ResultCountResolver = (selection: Selection) => number | Promise<number>;
interface FacetOption { id: string; label: string; count?: number }
interface RangePreset { id: string; label: string; min?: number; max?: number }
interface Facet {
id: string; label: string; kind: FacetKind;
options?: FacetOption[]; searchable?: boolean; selectAll?: boolean; columns?: 1 | 2;
min?: number; max?: number; step?: number; presets?: RangePreset[]; slider?: boolean;
presentation?: Presentation; applyMode?: ApplyMode;
}
interface ChipSpec {
facetId: string; kind: ChipKind; label?: string; optionId?: string;
leadingIcon?: ReactNode; badge?: ChipBadge; removable?: boolean;
pinActiveFirst?: boolean; opens?: Presentation;
}
interface RangeValue { min?: number; max?: number }
interface Selection {
options: Record<string, string[]>;
ranges: Record<string, RangeValue>;
}
interface ResultCountState { count: number | null; status: ResultCountStatus }
interface QuickFilterColors {
accent: string; accentText: string; success: string; surface: string; surfaceAlt: string;
border: string; text: string; textMuted: string; backdrop: string; chipBg: string;
chipText: string; chipActiveBg: string; chipActiveBorder: string; badgeBg: string;
badgeText: string; cta: string; ctaText: string;
}
interface QuickFilterTheme {
scheme: ColorScheme; colors: QuickFilterColors;
radius: { chip: number; panel: number; button: number };
spacing: { chipGapX: number; chipPadX: number; chipPadY: number; panelPad: number };
chipActiveStyle: ChipActiveStyle;
}
interface QuickFilterStrings {
sort: string; filter: string; apply: string; clear: string; clearAll: string;
selectAll: string; reset: string; close: string; back: string; priceMin: string; priceMax: string;
searchPlaceholder: (label: string) => string;
resultCount: (n: number) => string;
facetCount: (n: number) => string;
removeLabel: (label: string) => string;
}
// helper
const emptySelection: () => Selection;