Implementation:TobikoData Sqlmesh FilterableList
| Knowledge Sources | |
|---|---|
| Domains | Web_UI, Components |
| Last Updated | 2026-02-07 20:00 GMT |
Overview
A generic list component with integrated fuzzy search filtering using Fuse.js that displays item counts and empty states.
Description
The FilterableList component provides a search-enabled list interface using Fuse.js for fuzzy matching. It renders a search input at the top, a live counter badge showing filtered/total counts, and delegates item rendering to a children function with filtered results. The component includes a resetSearch callback in the render props for programmatic search clearing. When no results match the search, it displays an EmptyMessage component. The search input uses the Input component with type="search" and includes click propagation prevention to avoid triggering parent handlers.
Usage
Use FilterableList for any collection of items that benefits from search filtering such as model lists, option selectors, or data tables. Configure filterOptions to customize Fuse.js behavior (keys to search, thresholds, etc.). The component is fully generic and works with any item type through TypeScript generics.
Code Reference
Source Location
- Repository: TobikoData_Sqlmesh
- File: web/common/src/components/VirtualList/FilterableList.tsx
Signature
export interface FilterableListProps<TItem> {
items: TItem[]
filterOptions?: IFuseOptions<TItem>
disabled?: boolean
placeholder?: string
autoFocus?: boolean
className?: string
children: (options: TItem[], resetSearch: () => void) => React.ReactNode
}
export function FilterableList<TItem>({
items,
disabled,
placeholder,
autoFocus,
filterOptions,
className,
children,
}: FilterableListProps<TItem>) {
// Implementation
}
Import
import { FilterableList } from '@sqlmesh-common/components/VirtualList/FilterableList'
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| items | TItem[] | Yes | Array of items to filter |
| children | (items: TItem[], resetSearch: () => void) => React.ReactNode | Yes | Render function receiving filtered items and reset callback |
| filterOptions | IFuseOptions<TItem> | No | Fuse.js configuration for search behavior |
| disabled | boolean | No | Disable search input |
| placeholder | string | No | Search input placeholder text |
| autoFocus | boolean | No | Auto-focus search input on mount |
| className | string | No | Additional CSS classes for container |
Outputs
| Name | Type | Description |
|---|---|---|
| element | React.ReactElement | Container with search input, counter, and filtered results |
Usage Examples
// Basic string array
<FilterableList
items={['Apple', 'Banana', 'Cherry', 'Date']}
placeholder="Search fruits..."
filterOptions={{ threshold: 0.3 }}
>
{(filteredItems) => (
<ul>
{filteredItems.map(item => (
<li key={item}>{item}</li>
))}
</ul>
)}
</FilterableList>
// Complex objects with custom search keys
interface Model {
name: string
type: string
description: string
}
<FilterableList<Model>
items={models}
placeholder="Search models..."
filterOptions={{
keys: ['name', 'description'],
threshold: 0.4,
}}
>
{(filtered, resetSearch) => (
<div>
{filtered.map(model => (
<ModelCard
key={model.name}
model={model}
onSelect={() => {
handleSelect(model)
resetSearch() // Clear search after selection
}}
/>
))}
</div>
)}
</FilterableList>
// Auto-focused search
<FilterableList
items={options}
autoFocus={true}
placeholder="Type to filter..."
>
{(items) => <OptionList items={items} />}
</FilterableList>
// Disabled state
<FilterableList
items={items}
disabled={isLoading}
placeholder="Loading..."
>
{(items) => <ItemGrid items={items} />}
</FilterableList>
Technical Details
Fuse.js Integration
The component creates a new Fuse instance on each render with the current items and filterOptions. Search results are mapped from Fuse's result format (with score, indices, etc.) to just the item objects.
Counter Display
The counter badge shows:
- Full count: When not filtering, displays total item count
- Filtered count: When filtering, displays "X / Y" where X is filtered count and Y is total