@wirdestack/react-filter
v2.1.1
Published
A small React attribute filter with typed filter semantics
Downloads
77
Readme
React-filter
React-filter is a small attribute filter leveraging @material/ui for graphic components.
Table of content
Motivation
I needed a lightweight generic way to filter attributes on objects in an efficient manner.
Lightweight for me means no deep dependencies making upgrading your project complex.
I built a few components and used them in my own project and once I had a need for it in multiple projects I decided to make an open source library out of it.
Requirements
- React >= 19
- @mui/material => 6.4.1
How to install
npm i @wirdestack/react-filterHow to use
Simple example
import { useFilter, FilterChip, FilterSlider, FilterToggle, FilterSelect } from '@wirdestack/react-filter';
import type { FilterStructure, MultiSelectOptions, RangeOptions, BooleanChoice, SingleSelectOptions } from '@wirdestack/react-filter';
type Product = {
id: number;
name: string;
amount: string;
color: string;
brandName: string;
width: number;
height: number;
price: number;
quickDelivery: boolean;
};
type Products = ReadonlyArray<Product>;
type Params = Readonly<{
products: Products
}>;
const filterStructure: FilterStructure<Product> = {
color: { filterType: 'single-select', valueType: 'string', sort: 'asc' },
brandName: { filterType: 'multi-select', valueType: 'string', sort: 'asc' },
width: { filterType: 'multi-select', valueType: 'number', sort: 'desc' },
height: { filterType: 'range' },
price: { filterType: 'range' },
quickDelivery: { filterType: 'boolean' },
};
export default function ProductsWithFilter({ products }: Params) {
const [currentFilter, setCurrentFilter] = useState({});
const { options, filteredItems, availableOptions } = useFilter<Product>(products, filterStructure, currentFilter);
return <div className="products-with-filter">
<div className="filter">
<FilterSelect
label="Color"
filterName="color"
options={options['color'] as SingleSelectOptions}
availableOptions={availableOptions['color'] as SingleSelectOptions}
currentFilter={currentFilter}
filter={(filter) => setCurrentFilter(filter)}
/>
<FilterChip
label="Brand"
filterName="brandName"
options={options['brandName'] as MultiSelectOptions}
availableOptions={availableOptions['brandName'] as MultiSelectOptions}
currentFilter={currentFilter}
filter={(filter) => setCurrentFilter(filter)}
/>
<FilterChip
label="Width"
filterName="width"
options={options['width'] as MultiSelectOptions}
availableOptions={availableOptions['width'] as MultiSelectOptions}
currentFilter={currentFilter}
filter={(filter) => setCurrentFilter(filter)}
/>
<FilterSlider
label="Height"
filterName="height"
options={options['height'] as RangeOptions}
availableOptions={availableOptions['height'] as RangeOptions}
currentFilter={currentFilter}
filter={(filter) => setCurrentFilter(filter)}
unit={'cm'}
/>
<FilterSlider
label="Price"
filterName="price"
options={options['price'] as RangeOptions}
availableOptions={availableOptions['price'] as RangeOptions}
currentFilter={currentFilter}
filter={(filter) => setCurrentFilter(filter)}
unit={'€'}
unitAsPrefix={true}
/>
<FilterToggle
label="Only quick delivery"
filterName="quickDelivery"
value={currentFilter['quickDelivery'] as BooleanChoice}
currentFilter={currentFilter}
filter={(filter) => setCurrentFilter(filter)}
/>
</div>
<ProductList products={filteredItems} />
</div>;
}Optional if you want to style your component, add in your CSS somewhere:
:root {
--react-filter-distance: 8px; /* Row gaps and padding will be base on this. */
--react-filter-color: #9BCAC5; /* Your project's primary color. */
/*OR*/
--distance: 8px;
--primary-color: #9BCAC5; /* Your project's primary color? */
--react-filter-text-color: white; /* If you want to override text-color (on dark background for instance). */
/* Add this to decide to decide what language to use for the toggle button. Default is swedish. */
--react-filter-yes: 'Yes';
--react-filter-no: 'No';
}Note:
filterTypedescribes filter behavior, not the UI component used to render it. For example,multi-selectis currently rendered withFilterChip, but could be rendered differently in the future. There is nothing stopping you from just creating your own UI component to use for the filter, they are small and not complicated.
API
Component API
| Component | Description | | -------------- | ----------------------------------------------------------------- | | FilterChip | Will render a UI for a multi-select filter. | | FilterSelect | Will render a UI for a single-select filter. | | FilterSlider | Will render a UI for a range filter. | | FilterToggle | Will render a UI for a boolean filter. | | FilterChipSkeleton | A placeholder for FilterChip while the page loads if you want less CLS on your site. | | FilterSliderSkeleton | A placeholder for FilterSlider while the page loads if you want less CLS on your site. |
Hook API
| Hook | Description | | ---------------- | ----------------------------------------------------------------- | | useFilter | Takes the following params: - Array of object to filter. - The filter structure that defines each filter's behavior. - Current filter choices.Returns an object with the following:- options: Options that can be filtered on.- filteredItems: The items that matched the current filter.- availableOptions: Where options contains the current selected options, this contains all the available options you can pick. |
Contributing
Anyone is free to open a PR and contribute to this project... just be civilized!
Also, please join in on the discussions, feedback is appreciated.
