Filter ButtonV2
Filter Button is a component with an inline label and highlighted value. It lets users choose one or more items from an options menu.
Use a Filter Button to offer a list of choices where multiple selection is possible.
Example
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry' }, { label: 'peach', value: 'peach' }, { label: 'pear', value: 'pear' }, { label: 'grapefruit', value: 'grapefruit' }, { label: 'blackberry', value: 'blackberry' }, { label: 'strawberry', value: 'strawberry' }, { label: 'pineapple', value: 'pineapple' } ]; const [selectedItems, setSelectedItems] = useState(items); return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} showResetButton /> ); }
Variants
Anchor Size
The anchor is available in two sizes: small and medium can be accessed using size prop.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' } ]; const initialSelectedItems = [ { label: 'apple', value: 'apple' } ]; const [selectedItems, setSelectedItems] = useState(initialSelectedItems); return ( <div style={{ display: 'flex', gap: Spacing10 }}> <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} size="small" /> <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} size="medium" /> </div> ); }
Custom Controls
You have Search input and SelectAll checkbox shown by default, which can be hidden using showSearch and showSelectAll props.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry' }, { label: 'peach', value: 'peach' }, { label: 'pear', value: 'pear' } ]; const [selectedItems, setSelectedItems] = useState(items); return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} showResetButton showSearch={false} showSelectAll={false} /> ); }
Custom List Component
You can use a customList property to define custom component for filter items.
Utilize this property to customize the component of the specific filter items. Please keep in mind that you will be responsible for managing styles and keyboard navigation if you opt to pass a custom component. This functionality is most effectively employed in conjunction with the FilterButtonV2Context context.
function MyFilterButtonV2() { const CustomListComponent = ({ label, value, checked, onClick, onKeyDown }) => { const context = useContext(FilterButtonV2Context); // Get all values from context const { setSelectedItems, selectedItems, setSearchValue, setAreCheckedItemsChanged } = context; console.log({ selectedItems }); return ( <div style={{ paddingLeft: '10px' }}> <Switch checked={checked} size="small" label={label} labelPosition="right" onChange={onClick} onKeyDown={onKeyDown} /> </div> ); }; const apps = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' } ]; const initialSelectedItems = [ { label: 'banana', value: 'banana' } ]; const [initialValues, setInitialValues] = useState(initialSelectedItems); return ( <FilterButtonV2 name="Fruits" items={apps} selectedItems={initialValues} onApply={setInitialValues} customList={CustomListComponent} itemSize={48} /> ); }
Custom Sorting
You can use sortPredicate property to have custom sorting on the results when typing your query.
In this example when searching for 'us' or 'ru', unlike the default sorting, 'United States (US)' or 'Russia (RU)' will appear first, respectively.
function MyFilterButtonV2() { const items = [ { label: 'Cyprus (CY)', value: 'cyprus' }, { label: 'United States (US)', value: 'united_states' }, { label: 'United Kingdom (UK)', value: 'united_kingdom' }, { label: 'Belgium (BE)', value: 'belgium' }, { label: 'Germany (DE)', value: 'germany' }, { label: 'Russia (RU)', value: 'russia' }, { label: 'Belarus (BY)', value: 'belarus' }, { label: 'Italy (IT)', value: 'italy' }, { label: 'China (CN)', value: 'china' }, { label: 'France (FR)', value: 'france' } ]; const [selectedItems, setSelectedItems] = useState([]); return ( <FilterButtonV2 showResetButton name="Countries" items={items} sortPredicate={(a, b, searchValue) => { const abbrRegex = new RegExp(`\\b${searchValue}\\b`, 'gi'); return ( Number(abbrRegex.test(b.label)) - Number(abbrRegex.test(a.label)) ); }} selectedItems={selectedItems} onApply={setSelectedItems} /> ); }
Default Items
You can provide default items which will be used to populate filter once user clicks reset. If not specified filter with multiple selection will reset all items and with single selction filter will reset to initially selected item
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'kiwi', value: 'kiwi' }, { label: 'pear', value: 'pear' }, { label: 'dragon fruit', value: 'dragon fruit' }, { label: 'plum', value: 'plum' }, { label: 'tangerine', value: 'tangerine' }, { label: 'durian', value: 'durian' }, { label: 'peach', value: 'peach' }, { label: 'mango', value: 'mango' } ]; const initialSelectedItems = [ { label: 'apple', value: 'apple' } ]; const defaultItems = [ { label: 'mango', value: 'mango' } ]; const [multipleSelectedItems, setMultipleSelectedItems] = useState(initialSelectedItems); const [singleSelectedItems, setSingleSelectedItems] = useState(initialSelectedItems); return ( <div style={{ display: 'flex', gap: Spacing10 }}> <FilterButtonV2 showResetButton name="Multiple fruits" items={items} defaultItems={defaultItems} selectedItems={multipleSelectedItems} onApply={setMultipleSelectedItems} /> <FilterButtonV2 showResetButton multiple={false} name="Single fruit" items={items} defaultItems={defaultItems} selectedItems={singleSelectedItems} onApply={setSingleSelectedItems} /> </div> ); }
Description
A user can add a description to the option by using the description prop
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple', description: 'I am a description for apple' }, { label: 'banana', value: 'banana' }, { label: 'kiwi', value: 'kiwi' }, { label: 'pear', value: 'pear' }, { label: 'dragon fruit', value: 'dragon fruit', description: 'I am a description for dragon fruit' }, { label: 'plum', value: 'plum' }, { label: 'tangerine', value: 'tangerine' }, { label: 'durian', value: 'durian' }, { label: 'peach', value: 'peach' }, { label: 'mango', value: 'mango' } ]; const initialSelectedItems = [ { label: 'apple', value: 'apple' } ]; const [multipleSelectedItems, setMultipleSelectedItems] = useState(initialSelectedItems); const [singleSelectedItems, setSingleSelectedItems] = useState(initialSelectedItems); return ( <div style={{ display: 'flex', gap: Spacing10 }}> <FilterButtonV2 showResetButton name="Multiple fruits" items={items} selectedItems={multipleSelectedItems} onApply={setMultipleSelectedItems} /> <FilterButtonV2 showResetButton multiple={false} name="Single fruit" items={items} selectedItems={singleSelectedItems} onApply={setSingleSelectedItems} /> </div> ); }
Disable Sort when less items
Sorting is disabled by default when there are less than 6 items. This does not apply to search results.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry' }, { label: 'pineapple', value: 'pineapple' } ]; const initialSelectedItems = [ { label: 'pineapple', value: 'pineapple' }, { label: 'cherry', value: 'cherry' } ]; const [selectedItems, setSelectedItems] = useState(initialSelectedItems); return ( <> <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} /> </> ); }
Disabled
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' } ]; const initialSelectedItems = [ { label: 'apple', value: 'apple' } ]; const [selectedItems, setSelectedItems] = useState(initialSelectedItems); return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} disabled /> ); }
Disabled Item
We can disable the FilterItem by passing disabled prop in the item object.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana', disabled: true }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry', disabled: true }, { label: 'pineapple', value: 'pineapple' }, { label: 'pear', value: 'pear' }, { label: 'grapefruit', value: 'grapefruit' }, { label: 'blackberry', value: 'blackberry' }, { label: 'strawberry', value: 'strawberry' }, { label: 'grapes', value: 'grapes' } ]; const initialSelectedItems = [ { label: 'pineapple', value: 'pineapple' }, { label: 'cherry', value: 'cherry' } ]; const [selectedItems, setSelectedItems] = useState(initialSelectedItems); return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} /> ); }
disableSelectedSort
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry' }, { label: 'pineapple', value: 'pineapple' }, { label: 'pear', value: 'pear' }, { label: 'grapefruit', value: 'grapefruit' }, { label: 'blackberry', value: 'blackberry' }, { label: 'strawberry', value: 'strawberry' }, { label: 'grapes', value: 'grapes' } ]; const initialSelectedItems = [ { label: 'pineapple', value: 'pineapple' }, { label: 'cherry', value: 'cherry' } ]; const [selectedItems, setSelectedItems] = useState(initialSelectedItems); return ( <> <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} disableSelectedSort /> </> ); }
disableSort
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry' }, { label: 'peach', value: 'peach' }, { label: 'pear', value: 'pear' }, { label: 'grapefruit', value: 'grapefruit' }, { label: 'blackberry', value: 'blackberry' }, { label: 'strawberry', value: 'strawberry' }, { label: 'pineapple', value: 'pineapple' } ]; const initialSelectedItems = [ { label: 'pineapple', value: 'pineapple' } ]; const [selectedItems, setSelectedItems] = useState(initialSelectedItems); return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} disableSort /> ); }
disableSort - Custom Sorting with disabled default sorting
Here is an example of using custom sorting when defaut sorting is disabled.
function MyFilterButtonV2() { const items = [ { label: 'Cyprus (CY)', value: 'cyprus' }, { label: 'United States (US)', value: 'united_states' }, { label: 'United Kingdom (UK)', value: 'united_kingdom' }, { label: 'Belgium (BE)', value: 'belgium' }, { label: 'Germany (DE)', value: 'germany' }, { label: 'Russia (RU)', value: 'russia' }, { label: 'Belarus (BY)', value: 'belarus' }, { label: 'Italy (IT)', value: 'italy' }, { label: 'China (CN)', value: 'china' }, { label: 'France (FR)', value: 'france' } ]; const [selectedItems, setSelectedItems] = useState([]); return ( <FilterButtonV2 showResetButton name="Countries" items={items} sortPredicate={(a, b, searchValue) => { const abbrRegex = new RegExp(`\\b${searchValue}\\b`, 'gi'); return ( Number(abbrRegex.test(b.label)) - Number(abbrRegex.test(a.label)) ); }} selectedItems={selectedItems} onApply={setSelectedItems} disableSort /> ); }
Empty state custom component
You can use a emptyStateComponent property to define the empty state component for the filter instead of the default one. Empty state is shown when there are no items to display (e.g. when we have API error and initial items array is empty):
function MyFilterButtonV2() { const items = []; const [selectedItems, setSelectedItems] = useState([]); const EmptyState = () => ( <div style={{ padding: '20px', textAlign: 'center' }}> <Icon name="Info" size="large" color="neutralSecondary" /> <div>No data to display</div> </div> ); return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} emptyStateComponent={EmptyState} /> ); }
Default empty state(uses empty-state-message label to set the message):
function MyFilterButtonV2() { const items = []; const [selectedItems, setSelectedItems] = useState([]); return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} /> ); }
Enable Zero Selection
To have no filters applied, you can enable the prop enableZeroSelection to true.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry' }, { label: 'peach', value: 'peach' }, { label: 'pear', value: 'pear' }, { label: 'grapefruit', value: 'grapefruit' }, { label: 'blackberry', value: 'blackberry' }, { label: 'strawberry', value: 'strawberry' }, { label: 'pineapple', value: 'pineapple' } ]; const [selectedItems, setSelectedItems] = useState(items); return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} showResetButton enableZeroSelection /> ); }
Footer Warning Message
You can use this prop to display a warning message in the footer.
Important note: footerWarningMessage prop and the Reset Button cannot be used at the same time.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' } ]; const initialSelectedItems = [ { label: 'apple', value: 'apple' } ]; const [selectedItems, setSelectedItems] = useState(initialSelectedItems); return ( <div style={{ display: 'flex', gap: Spacing10 }}> <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} footerWarningMessage="Select a maximum of 6 apps." /> </div> ); }
Full width trigger
You can use isFullWidthTrigger property to allow the trigger to take the available width. If isFullWidthTrigger is true the menu takes the same width as the trigger.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry' }, { label: 'peach', value: 'peach' }, { label: 'pear', value: 'pear' }, { label: 'grapefruit', value: 'grapefruit' }, { label: 'blackberry', value: 'blackberry' }, { label: 'strawberry', value: 'strawberry' }, { label: 'pineapple', value: 'pineapple' } ]; const [selectedItems, setSelectedItems] = useState(items); return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} showResetButton isFullWidthTrigger /> ); }
Icons, App Icons and Platforms
function MyFilterButtonV2() { const items =[ { value: 'amazingmarket', label: 'Amazing Market', iconName: 'DuoStackedBarChart', platform: [ "PlatformWindowsFilled" ] }, { value: 'cryptoharvest', label: 'Crypto Harvest', iconName: 'DuoBarChart', platform: [ 'PlatformAndroidFilled', 'PlatformVizioTVFilled' ] }, { value: 'piechart', label: 'DuoTone PieChart', iconName: 'DuoPieChart' }, { value: 'leardroid', label: 'Learn Droid with loooooong text', iconName: 'DuoBarChart', platform: [ 'PlatformAndroidFilled', 'PlatformVizioTVFilled', 'PlatformIosFilled', 'PlatformWindowsFilled' ] } ]; const [selectedItems, setSelectedItems] = useState(items); return ( <FilterButtonV2 name="Apps" items={items} selectedItems={selectedItems} onApply={setSelectedItems} showResetButton /> ); }
InfoText
A text value to show information related to the selection.
You can change the position of the info text to be on top of the FilterButtonV2 as well.
Please avoid using the Info Text on top of the FilterButtonV2 when you also need the optional label.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry' }, { label: 'peach', value: 'peach' }, { label: 'pear', value: 'pear' }, { label: 'grapefruit', value: 'grapefruit' }, { label: 'blackberry', value: 'blackberry' }, { label: 'strawberry', value: 'strawberry' }, { label: 'pineapple', value: 'pineapple' } ]; const [selectedItems, setSelectedItems] = useState(items); return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} showResetButton infoText='Sample info Text' /> ); }
We also support text tags inside the Info Text. Like strong, b, i and a.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry' }, { label: 'peach', value: 'peach' }, { label: 'pear', value: 'pear' }, { label: 'grapefruit', value: 'grapefruit' }, { label: 'blackberry', value: 'blackberry' }, { label: 'strawberry', value: 'strawberry' }, { label: 'pineapple', value: 'pineapple' } ]; const [selectedItems, setSelectedItems] = useState(items); const infoText = `Info <b>text</b> really <i>long</i> that <a href='#'> goes </a> on to a <strong> second </strong>line`; return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} showResetButton infoText={infoText} /> ); }
Invalid State
A user can set a invalid state when the selection is improper.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry' }, { label: 'peach', value: 'peach' }, { label: 'pear', value: 'pear' }, { label: 'grapefruit', value: 'grapefruit' }, { label: 'blackberry', value: 'blackberry' }, { label: 'strawberry', value: 'strawberry' }, { label: 'pineapple', value: 'pineapple' } ]; const [selectedItems, setSelectedItems] = useState(items); return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} showResetButton infoText={'I am sample invalid infoText'} invalid /> ); }
isApplyButtonDisabled
You can use this prop to disable the Apply button.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' } ]; const initialSelectedItems = [ { label: 'apple', value: 'apple' } ]; const [selectedItems, setSelectedItems] = useState(initialSelectedItems); return ( <div style={{ display: 'flex', gap: Spacing10 }}> <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} isApplyButtonDisabled={true} /> </div> ); }
isGroupLabel
You can use this prop to add a Group Label.
function MyFilterButtonV2() { const items = [ { label: 'Fruits', value: 'fruits', isGroupLabel: true }, { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry' }, { label: 'pineapple', value: 'pineapple' }, { label: 'Vegetables', value: 'vegetables', isGroupLabel: true }, { label: 'Beans', value: 'beans' }, { label: 'Potato', value: 'potato' }, { label: 'Onion', value: 'onion' }, { label: 'Spinach', value: 'spinach' }, { label: 'Tomato', value: 'tomato' }, ]; const initialSelectedItems = [ { label: 'apple', value: 'apple' }, { label: 'Spinach', value: 'spinach' } ]; const [selectedItems, setSelectedItems] = useState(initialSelectedItems); return ( <div style={{ display: 'flex', gap: Spacing10 }}> <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} disableSelectedSort /> </div> ); }
Loading More Data
The component supports virtual infinite loading by adding following props:
onLoadMoreDataa callback function to load more data.hasMoreDataisLoadingMoreDataloadingMoreDataLabelcustom label of status indicator.
To integrate virtual infinite loading with React Query please refer to useInfiniteQuery hook and this example.
function MyFilterButtonV2() { const generateMoreData = useCallback( (offset = 0, chunkSize = 25) => Array.from({ length: chunkSize }, (_, index) => { const id = offset + index + 1; return { label: `Label ${id}`, value: `value_${id}`, }; }), [] ); const maxNumberOrRows = 100; const initialData = useMemo(() => generateMoreData(), [generateMoreData]); const [items, setItems] = useState(initialData); const [selectedItems, setSelectedItems] = useState(initialData); const [isLoadingMoreData, setIsLoadingMoreData] = useState(false); const onLoadMoreData = useCallback(() => { setIsLoadingMoreData(true); setTimeout(() => { const generatedData = generateMoreData(items.length); setItems((preItems) => [...preItems, ...generatedData]); setSelectedItems((selectedItems) => [...selectedItems, ...generatedData]); setIsLoadingMoreData(false); }, 3000); }, [items.length, generateMoreData]); return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} showResetButton hasMoreData={items.length < maxNumberOrRows} isLoadingMoreData={isLoadingMoreData} onLoadMoreData={onLoadMoreData} /> ); }
Loading State
You can use a isLoading property in order to display the loading indicator.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry' }, { label: 'pear', value: 'pear' }, { label: 'blackberry', value: 'blackberry' }, { label: 'strawberry', value: 'strawberry' }, { label: 'pineapple', value: 'pineapple' } ]; const initialSelectedItems = [ { label: 'apple', value: 'apple' } ]; const [selectedItems, setSelectedItems] = useState(initialSelectedItems); return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} isLoading /> ); }
Menu Size
The menu list is available in three sizes: small, medium and large can be accessed using menuSize prop. It is ignored if isFullWidthTrigger is true. In this case the menu takes the same width as the trigger.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry' }, { label: 'peach', value: 'peach' }, { label: 'pear', value: 'pear' }, { label: 'grapefruit', value: 'grapefruit' }, { label: 'blackberry', value: 'blackberry' }, { label: 'strawberry', value: 'strawberry' }, { label: 'pineapple', value: 'pineapple' } ]; const initialSelectedItems = [ { label: 'apple', value: 'apple' } ]; const [selectedItems, setSelectedItems] = useState(initialSelectedItems); return ( <div style={{ display: 'flex', gap: Spacing10 }}> <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} menuSize="small" /> <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} menuSize="medium" /> <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} menuSize="large" /> </div> ); }
Mode Shifter
In FilterButtonV2 we have a mode shifter which can be enabled when modeShifter is true and onModeChange handler is provided.
We have 2 mode include and exclude, which can be controlled using onModeChange handler which uses an argument of either of 2 modes.
There are 2 cases where the exclude selection jumps to the it equivalant include state.
Nothing Selected in Exclude = All Selected in Include
All Items Selected in Exclude = Nothing Seleted in Include.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry' }, { label: 'peach', value: 'peach' }, { label: 'pear', value: 'pear' }, { label: 'grapefruit', value: 'grapefruit' }, { label: 'blackberry', value: 'blackberry' }, { label: 'strawberry', value: 'strawberry' }, { label: 'pineapple', value: 'pineapple' } ]; const [selectedItems, setSelectedItems] = useState(items); const [modeType, setModeType] = useState('include'); const onModeChange = (value) => { setModeType(value); }; const onApplyToFilter = (selectedItems, mode) => { console.log(selectedItems, mode); setSelectedItems(selectedItems); }; return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={onApplyToFilter} showResetButton modeShifter modeType={modeType} onModeChange={onModeChange} /> ); }
You can also change the Mode labels using the modeLabels property.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry' }, { label: 'peach', value: 'peach' }, { label: 'pear', value: 'pear' }, { label: 'grapefruit', value: 'grapefruit' }, { label: 'blackberry', value: 'blackberry' }, { label: 'strawberry', value: 'strawberry' }, { label: 'pineapple', value: 'pineapple' } ]; const [selectedItems, setSelectedItems] = useState(items); const [modeType, setModeType] = useState('include'); const onModeChange = (value) => { setModeType(value); }; const modeLabels = { include: 'enthalten', exclude: 'ausschließen' }; return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} showResetButton modeShifter modeType={modeType} onModeChange={onModeChange} modeLabels={modeLabels} /> ); }
onSearch (Async Search)
You can use the onSearch prop to provide an async search functionality.
Pay attention to these points:
- debounce onSearch calls if needed
- cancel/abort previous search requests, while typing/making a new one
- apply selected to initial items. If initial items does not contain them. So the user can see all selected items.
function FilterButtonV2WithAsyncSearch() { const generateMoreData = useCallback( (searchString: string = '') => Array.from({ length: 10 }, (_, index) => { const id = index + 1; return { label: `Label ${id} ${searchString}`, value: `value_${id}_${searchString}`, }; }), [] ); const initialData = useMemo(() => generateMoreData(), [generateMoreData]); const [items, setItems] = useState(initialData); const [selectedItems, setSelectedItems] = useState(initialData.slice(0, 2)); const [preSelectedItems, setPreSelectedItems] = useState(selectedItems); const [isLoading, setIsLoading] = useState(false); const loadingTimer = useRef<NodeJS.Timeout | null>(null); const updateInitialItems = useCallback((selectedItems: any[]) => { const missedSelectedItems = selectedItems.filter(item => { return !initialData.some(initialItem => item.value === initialItem.value); }); const initialDataAndSelectedItems = initialData.concat(missedSelectedItems); setItems(initialDataAndSelectedItems); }, [initialData]); const cancelSearchRequest = useCallback(() => { loadingTimer.current && clearTimeout(loadingTimer.current); setIsLoading(false); }, []); const onSearch = useCallback((searchString: string) => { console.log('onSearch', searchString); cancelSearchRequest(); if (searchString.length > 0) { setIsLoading(true); loadingTimer.current = setTimeout(() => { const generatedData = generateMoreData(searchString); setItems(generatedData); setIsLoading(false); }, 1500); } else { updateInitialItems(preSelectedItems); setIsLoading(false); } }, [initialData, preSelectedItems, generateMoreData]); const onApply = useCallback((appliedItems: any[]) => { console.log('onApply', appliedItems); setSelectedItems(appliedItems); updateInitialItems(appliedItems); cancelSearchRequest(); }, []); const onReset = useCallback(() => { const initialSelectedItems = initialData.slice(0, 2); return initialSelectedItems; }, [initialData]); const onHide = useCallback(() => { console.log('onHide', selectedItems); updateInitialItems(selectedItems); cancelSearchRequest(); }, [selectedItems]); return ( <FilterButtonV2 name="Async Search" items={items} selectedItems={selectedItems} onApply={onApply} isLoading={isLoading} onSearch={onSearch} onHide={onHide} showResetButton onReset={onReset} onSelectionChange={setPreSelectedItems} /> ); }
onSelectionChange
The onSelectionChange prop is an onChange callback. You can use this prop to send information about the selected items to the parent component.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry' }, { label: 'peach', value: 'peach' }, { label: 'pear', value: 'pear' }, { label: 'grapefruit', value: 'grapefruit' }, { label: 'blackberry', value: 'blackberry' }, { label: 'strawberry', value: 'strawberry' }, { label: 'pineapple', value: 'pineapple' } ]; const initialSelectedItems = [ { label: 'apple', value: 'apple' } ]; const [selectedItems, setSelectedItems] = useState(initialSelectedItems); const [message, setMessage] = useState(''); const [isDisabled, setIsDisabled] = useState(false); const onSelectionChange = (items) => { if(items.length > 6) { setMessage('Select a maximum of 6 apps.'); setIsDisabled(true); } else { setMessage(''); setIsDisabled(false); } } const renderValue = () => { return ( <div style={{ display: 'flex', alignItems: 'center' }}> <Icon name="Pin" css={{ marginRight: Spacing10 }} /> <span>Pin apps</span> </div> ); }; return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} onSelectionChange={onSelectionChange} footerWarningMessage={message} renderValue={renderValue} isApplyButtonDisabled={isDisabled} /> ); }
Render Items
You can use a renderItem property to define custom render function for filter items.
The filter uses the virtualization so if you are about to change the height of items do not forget to specify an itemSize property.
function MyFilterButtonV2() { const apps = [ { label: 'apple', value: 'apple', iconName: 'DuoBarChart', platform: [ 'PlatformAndroidFilled', 'PlatformVizioTVFilled', 'PlatformIosFilled', 'PlatformWindowsFilled' ], description: 'a test description for FilterButtonV2 item', name: 'My name is Apple', subItems: [ { label: 'banana', value: 'banana' } ] }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' } ]; const initialSelectedItems = [ { label: 'banana', value: 'banana' } ]; const [selectedItems, setSelectedItems] = useState(initialSelectedItems); const renderItem = ({ label, value, iconName, platform, description, name, subItems }) => ( <div> <div style={{ display: 'flex', alignItems: 'center', width: '100%' }} > <div> {iconName && <Icon size="large" name={iconName} css={{ marginLeft: Spacing10 }} />} <span style={{ flex: 1, textAlign: 'left' }}>{label}</span> { name && value ? <span>{name + " " +value}</span> :null} </div> {platform && platform.length !==0 ? platform.map((item, i) => ( <Icon size="small" name={item} css={{ marginLeft: Spacing10 }} key={i} /> ) ) : null} </div> {description && <span>{description}</span>} {subItems && subItems.length !== 0 ? subItems.map((sub, i) => ( <span style={{paddingTop: "5px"}} key={i}>{sub.label + " I am a Sub Item"}</span> )) : null } </div> ); return ( <FilterButtonV2 name="Fruits" items={apps} selectedItems={selectedItems} onApply={setSelectedItems} renderItem={renderItem} itemSize={48} /> ); }
RenderValue
You can use a renderValue property to define custom render function for the filter value.
When specified this function is used to render a custom element within the trigger.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' } ]; const initialSelectedItems = [ { label: 'apple', value: 'apple' } ]; const [selectedItems, setSelectedItems] = useState(initialSelectedItems); const renderValue = () => { return ( <div style={{ display: 'flex', alignItems: 'center' }}> <Icon name="CogWheel" css={{ marginRight: Spacing10 }} /> <span>All fruits</span> <Badge color="negative" label="Custom label" css={{ marginLeft: Spacing10 }} /> </div> ); }; return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} renderValue={renderValue} /> ); }
Reset Button
You can use a showResetButton property in order to display the reset button.
The reset button selects all option items.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' } ]; const initialSelectedItems = [ { label: 'apple', value: 'apple' } ]; const [selectedItems, setSelectedItems] = useState(initialSelectedItems); return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} showResetButton /> ); }
Single Value Selection
You can use multiple property to define if you want to have multiple or single selection for defined options.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'kiwi', value: 'kiwi' }, { label: 'pear', value: 'pear' }, { label: 'dragon fruit', value: 'dragon fruit' }, { label: 'plum', value: 'plum' }, { label: 'tangerine', value: 'tangerine' }, { label: 'durian', value: 'durian' }, { label: 'peach', value: 'peach' }, { label: 'mango', value: 'mango' } ]; const initialSelectedItems = [ { label: 'apple', value: 'apple' } ]; const [selectedItems, setSelectedItems] = useState(initialSelectedItems); return ( <FilterButtonV2 showResetButton multiple={false} name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} /> ); }
Translate
You can use a getElementLabel property to define the text for all elements within the Filter.
This function will be called with one of the following values as an argument:
type FilterButtonV2TextElements =
| 'apply-button'
| 'reset-button'
| 'select-all-default'
| 'select-all-searched'
| 'loading-message'
| 'not-found-message'
| 'empty-state-message'
| 'all-selected-badge-label'
| 'search-input-placeholder'
Each value matches the element within the Filter, e.g. 'apply-button' specifies the label for the Apply button etc.
function MyFilterButtonV2() { const items = [ { label: 'apple', value: 'apple' }, { label: 'banana', value: 'banana' }, { label: 'orange', value: 'orange' }, { label: 'cherry', value: 'cherry' }, { label: 'peach', value: 'peach' }, { label: 'pear', value: 'pear' }, { label: 'grapefruit', value: 'grapefruit' }, { label: 'blackberry', value: 'blackberry' }, { label: 'strawberry', value: 'strawberry' }, { label: 'pineapple', value: 'pineapple' } ]; const initialSelectedItems = [ { label: 'apple', value: 'apple' } ]; const [selectedItems, setSelectedItems] = useState(initialSelectedItems); const getElementLabel = (element) => { if (element === 'apply-button') { return 'Hello'; } return 'world'; }; return ( <FilterButtonV2 name="Fruits" items={items} selectedItems={selectedItems} onApply={setSelectedItems} getElementLabel={getElementLabel} /> ); }
Props
| Name | Type | Default |
|---|---|---|
onApply * |
| — |
selectedItems * |
| — |
items * |
| — |
name * |
| — |
multiple |
| true |
defaultItems |
| — |
disabled |
| — |
invalid |
| — |
isLoading |
| — |
size |
| "small" |
menuSize |
| "small" |
itemSize |
| 32 |
showSearch |
| true |
showSelectAll |
| true |
showResetButton |
| — |
modeShifter |
| — |
enableZeroSelection |
| false |
modeType |
| — |
modeLabels |
| — |
onReset |
| — |
onHide |
| — |
onSearch |
| — |
onSelectionChange |
| — |
onModeChange |
| — |
renderItem |
| — |
renderValue |
| — |
getElementLabel |
| — |
searchPredicate |
| — |
sortPredicate |
| — |
id |
| — |
aria-label |
| — |
aria-labelledby |
| — |
zIndex |
| — |
isFullWidthTrigger |
| — |
isApplyButtonDisabled |
| — |
footerWarningMessage |
| — |
emptyStateComponent |
| — |
customList |
| — |
onLoadMoreData |
| — |
isLoadingMoreData |
| — |
hasMoreData |
| — |
loadingMoreDataLabel |
| — |
infoText |
| — |
disableSort |
| false |
disableSelectedSort |
| false |
data-{foo} Data attributes can be used by testing libraries to retrieve components or assert their existence |
| — |
| * - the prop is required. |