UI Filter Components
Relevant source files
The following files were used as context for generating this wiki page:
UI Filter Components provide the interactive layer for users to author and manage FilterState and FilterGroupNode data structures. These components translate user input—such as text entry, option selection, and date picking—into standardized filter nodes that are processed by the core library and database adapters.
The system is designed with a focus on performance, leveraging memoization and stable observer patterns to prevent unnecessary re-renders in large tables. It supports both flat filter bars and advanced visual group builders for nested AND/OR logic.
Sources: plans/048-filter-group-builder-ui.md:14-25, plans/025-ui-render-performance.md:14-20, packages/ui/README.md
Architecture and Data Flow
The UI filter system follows a unidirectional data flow where user interactions trigger state updates through dedicated hooks and managers. The FilterNode state layer preserves tree structures for nested logic while providing flat views for simpler UI representations like filter badges.
Component Interaction Flow
The following diagram illustrates how user input at the component level flows into the state management layer:
The diagram shows the transition from user input to serialized URL state and final database query execution.
Sources: plans/016-filternode-state-layer.md:28-40, plans/048-filter-group-builder-ui.md:65-72
Core Filter Components
The library provides several high-level components to manage filtering across different layouts and complexity levels.
Filter Bar
The FilterBar serves as the primary horizontal interface for managing active filters. It typically renders a list of filter badges representing the current FilterState. In version 0.6, the FilterBar remains flat, emitting an implicit-AND FilterNode for forward compatibility with nested groups.
Sources: packages/ui/src/components/filters/filter-bar.tsx, plans/048-filter-group-builder-ui.md:38-45
Faceted Filter Sidebar
The FacetedFilterSidebar provides a vertical interface that updates dynamically as filters are applied. It demonstrates filter-awareness and self-exclusion, meaning the sidebar options for a specific column are not narrowed by that column's own active filter.
Sources: packages/ui/src/components/filters/faceted-filter-sidebar.tsx, plans/029-marketing-showcase-dogfood.md:92-98
Filter Group Builder
Designed for complex query authoring, the FilterGroupBuilder allows users to create nested AND/OR logic. It enforces a depth-3 cap to ensure UI and SQL performance remain stable.
Sources: plans/048-filter-group-builder-ui.md:58-64
| Component | Description | Primary State Type |
|---|---|---|
FilterBar | Horizontal bar for active filters/badges. | FilterState[] |
FacetedFilterSidebar | Sidebar with dynamic counts for options. | FacetedValues |
FilterGroupBuilder | Visual tree builder for nested logic. | FilterGroupNode |
TextFilterInput | Standard input for text-based operators. | string[] |
Sources: plans/048-filter-group-builder-ui.md:58-64, packages/ui/src/components/filters/faceted-filter-sidebar.tsx
Filter Input Primitives
Filter inputs are the leaf nodes of the filtering UI. Each input is specialized for a specific data type and set of operators.
Specialized Inputs
- Text Filter Input: Handles operators like
contains,equals,startsWith, andregex. - Option Filter Input: Manages single and multi-select logic. It includes short-circuits for
isNullandisNotNulloperators, which emit no values. - Date Filter Input: Supports single date selection and date ranges.
- Number Filter Input: Handles numeric comparisons and ranges.
Sources: plans/042-ui-test-coverage.md:37-45, packages/ui/src/components/filters/inputs/text-filter-input.tsx
Input Value Emission
Filter inputs are characteristically unit-tested to ensure correct FilterState.values emission per operator.
// Example of TextFilterInput usage
<TextFilterInput
operator="contains"
value={currentValues}
onChange={(newValues) => handleFilterChange(columnId, 'contains', newValues)}
/>
Sources: packages/ui/src/components/filters/inputs/text-filter-input.tsx:1-20, plans/042-ui-test-coverage.md:55-62
Performance Optimization
To handle large datasets and frequent UI updates, the filter components utilize specific React performance patterns.
Stable Callbacks and Memoization
The MemoizedFilterBadge component is used within the filter bar to prevent re-rendering all badges when only a single filter is updated. This is supported by useCallback factories that create stable handlers for onUpdate and onRemove events.
Sources: plans/025-ui-render-performance.md:14-25, plans/025-ui-render-performance.md:44-50
Effect Churn Prevention
UI components avoid "effect churn" by ref-latching parent callbacks. This ensures that unstable callback props passed from parent components do not trigger unnecessary bridge effects or resubscriptions in hooks like useVirtualization.
Sources: plans/025-ui-render-performance.md:46-52
The sequence diagram represents the validation flow that occurs when a user modifies a filter value.
Sources: plans/042-ui-test-coverage.md:73-77, plans/004-validate-url-state.md:75-85
Summary
UI Filter Components in Better Tables bridge the gap between user interaction and complex database queries. By providing specialized inputs, faceted sidebars, and nested group builders, the system enables flexible data exploration. The architecture ensures that even as query complexity grows (e.g., nested OR groups), the UI remains performant through strict memoization and stable state management.