FilterMenu
FilterMenu allows a user to choose from a list of options, which can be filtered. It is a composable component which consists of a trigger (for toggling a popover), a search input (for filtering results), a listbox (to display options), and a popover (which contains the listbox when opened). In small screens (tablet and mobile), the Popover will be displayed as a Sheet.
Quick Start
- Installation
npm install @adaptavant/eds-core- Import
import { FilterMenu } from '@adaptavant/eds-core';
Default
Basic example
const initialOptions = [
{ code: "61", id: "AUS", name: "Australia" },
{ code: "64", id: "NZL", name: "New Zealand" },
{ code: "91", id: "IND", name: "India" },
{ code: "48", id: "POL", name: "Poland" },
{ code: "44", id: "GBR", name: "Scotland (UK)" },
{ code: "1", id: "USA", name: "United States" },
];
const [selectedOption, setSelectedOption] = React.useState();
const [searchTerm, setSearchTerm] = React.useState('');
function onClear(){
return setSearchTerm('');
}
function handleInputOnChange(event) {
return setSearchTerm(event.target.value);
}
const filteredOptions = searchTerm === "" ? initialOptions : initialOptions.filter((country) =>
country.name.toLowerCase().includes(searchTerm.toLowerCase())
);
function OptionLabel({ name, code }) {
return (
<Track as="span">
{name} +{code}
</Track>
);
}
function NoResults() {
return (
<Text className="text-secondary text-center text-body-12 py-4">
No matching results
</Text>
);
}
return (
<Field label="Select">
<FilterMenu>
<FilterMenuTrigger placeholder="Select Country">
{selectedOption ? <OptionLabel {...selectedOption} /> : null}
</FilterMenuTrigger>
<FilterMenuPopover>
<FilterMenuSearchField label="Search Items">
<FilterMenuSearchInput
onClear={onClear}
onChange={handleInputOnChange}
value={searchTerm}
placeholder="Search..."
/>
</FilterMenuSearchField>
<FilterMenuListbox
noResultsFallback={<NoResults />}
options={filteredOptions}
>
{(option) => (
<FilterMenuItem
id={option.id}
isSelected={selectedOption?.id === option.id}
onClick={() => {
setSelectedOption(option);
}}
>
<OptionLabel {...option} />
</FilterMenuItem>
)}
</FilterMenuListbox>
</FilterMenuPopover>
</FilterMenu>
</Field>
);
Currency Picker
Using FilterMenu's compound component API, we can easily build a CurrencyPicker component from scratch.
const countries = [
{ currency: 'US Dollar', currencyCode: 'USD', currencySymbol: '$', id: "ASM", name: "American Samoa" },
{ currency: 'East Caribbean dollar', currencyCode: 'XCD', currencySymbol: '$', id: "AIA", name: "Anguilla" },
{ currency: 'Australian dollar', currencyCode: 'AUD', currencySymbol: '$', id: "AUS", name: "Australia" },
{ currency: 'Central African CFA franc', currencyCode: 'XAF', currencySymbol: 'FCFA', id: "TCD", name: "Chad" },
{ currency: 'Falkland Islands pound', currencyCode: 'FKP', currencySymbol: '£', id: "FLK", name: "Falkland Islands (Malvinas)"},
{ currency: 'British pound', currencyCode: 'GBP', currencySymbol: '£', id: "GGY", name: "Guernsey"},
{ currency: 'British pound', currencyCode: 'GBP', currencySymbol: '£', id: "IMN", name: "Isle of Man"},
{ currency: 'Indian rupee', currencyCode: 'INR', currencySymbol: '₹', id: "IND", name: "India"},
{ currency: 'Lebanese pound', currencyCode: 'LBP', currencySymbol: '£', id: "LBN", name: "Lebanon"},
{ currency: 'New Zealand dollar', currencyCode: 'NZD', currencySymbol: '$', id: "NZL", name: "New Zealand"},
{ currency: 'United States dollar', currencyCode: 'USD', currencySymbol: '$', id: "TLS", name: "Timor-Leste"},
{ currency: 'Singapore dollar', currencyCode: 'SGD', currencySymbol: '$', id: "SGP", name: "Singapore"},
{ currency: 'United Arab Emirates dirham', currencyCode: 'AED', currencySymbol: 'إ.د', id: 'ARE', name: 'United Arab Emirates',},
{ currency: 'British pound', currencyCode: 'GBP', currencySymbol: '£', id: 'GBR', name: 'United Kingdom',},
{ currency: 'United States dollar', currencyCode: 'USD', currencySymbol: '$', id: 'USA', name: 'United States',},
];
const [selectedOption, setSelectedOption] = React.useState();
const [searchTerm, setSearchTerm] = React.useState('');
function onClear() {
return setSearchTerm('');
}
function handleInputOnChange(event) {
return setSearchTerm(event.target.value);
}
const filteredOptions = searchTerm === "" ? countries : countries.filter((country) =>
Object.values(country).map((value) =>
value.toLowerCase()
).join(" ").includes(searchTerm.toLowerCase())
);
function escapeRegExp(string) {
return string.replace(/[+$]/g, '\\$&');
}
function highlightMatchedContent(text, searchTerm) {
if (!searchTerm) return text;
const escapedSearchTerm = escapeRegExp(searchTerm);
const regex = new RegExp(`(${escapedSearchTerm})`, 'gi');
const parts = text.trim().split(regex);
return parts.map((part, index) =>
regex.test(part) ? (
<span className="font-stronger" key={index}>
{part}
</span>
) : (
part
)
);
}
function OptionLabel({ name, currencyCode, currencySymbol }) {
return (
<Track
className="gap-1"
classNames={{
center: 'grow-0',
}}
railEnd={<>- {highlightMatchedContent(currencyCode, searchTerm)} {highlightMatchedContent(currencySymbol, searchTerm)}</>}
>
<Track classNames={{ center: 'line-clamp-1'}}>
{highlightMatchedContent(name, searchTerm)}
</Track>
</Track>
);
}
function NoResults() {
return (
<Text className="text-secondary text-center text-body-12 py-4">
No matching results
</Text>
);
}
return (
<Field label="Currency Picker" className="w-60">
<FilterMenu popoverMatchReferenceWidth>
<FilterMenuTrigger placeholder="Select currency">
{selectedOption ? <OptionLabel {...selectedOption} /> : null}
</FilterMenuTrigger>
<FilterMenuPopover>
<FilterMenuSearchField label="Search Items">
<FilterMenuSearchInput
onClear={onClear}
onChange={handleInputOnChange}
value={searchTerm}
placeholder="Search..."
/>
</FilterMenuSearchField>
<FilterMenuListbox
noResultsFallback={<NoResults />}
options={filteredOptions}
>
{(option) => (
<FilterMenuItem
id={option.id}
isSelected={selectedOption?.id === option.id}
onClick={() => {
setSelectedOption(option);
}}
>
<OptionLabel {...option} />
</FilterMenuItem>
)}
</FilterMenuListbox>
</FilterMenuPopover>
</FilterMenu>
</Field>
);
Country Code Picker
To build a CountryCodePicker component from scratch, follow the code example below.
The following snippet uses useFilteredOptions, a custom hook that manages the search function and returns a filteredOptions array. It also utilises useDeferredValue to improve performance of expensive state updates and spreads some common functions like onClear and onChange to the FilterMenuSearchInput inside a popover via getSearchInputProps.
If you prefer to use your own custom state management, refer to the CurrencyPicker example provided above.
const countries = [
{ currency: 'US Dollar', currencyCode: 'USD', currencySymbol: '$', id: "ASM", name: "American Samoa", dailCode: '1684' },
{ currency: 'East Caribbean dollar', currencyCode: 'XCD', currencySymbol: '$', id: "AIA", name: "Anguilla", dailCode: '1264'},
{ currency: 'Australian dollar', currencyCode: 'AUD', currencySymbol: '$', id: "AUS", name: "Australia", dailCode: '61'},
{ currency: 'Canadian dollar', currencyCode: 'CAD', currencySymbol: '$', id: "CAN", name: "Canada", dailCode: '1'},
{ currency: 'Central African CFA franc', currencyCode: 'XAF', currencySymbol: 'FCFA', id: "TCD", name: "Chad", dailCode: '235'},
{ currency: 'Falkland Islands pound', currencyCode: 'FKP', currencySymbol: '£', id: "FLK", name: "Falkland Islands (Malvinas)", dailCode: '500'},
{ currency: 'British pound', currencyCode: 'GBP', currencySymbol: '£', id: "GGY", name: "Guernsey", dailCode: '44'},
{ currency: 'British pound', currencyCode: 'GBP', currencySymbol: '£', id: "IMN", name: "Isle of Man", dailCode: '44'},
{ currency: 'Indian rupee', currencyCode: 'INR', currencySymbol: '₹', id: "IND", name: "India", dailCode: '91'},
{ currency: 'Lebanese pound', currencyCode: 'LBP', currencySymbol: '£', id: "LBN", name: "Lebanon", dailCode: '961'},
{ currency: 'New Zealand dollar', currencyCode: 'NZD', currencySymbol: '$', id: "NZL", name: "New Zealand", dailCode: '64'},
{ currency: 'United States dollar', currencyCode: 'USD', currencySymbol: '$', id: "TLS", name: "Timor-Leste", dailCode: '670'},
{ currency: 'Singapore dollar', currencyCode: 'SGD', currencySymbol: '$', id: "SGP", name: "Singapore", dailCode: '65'},
{ currency: 'United Arab Emirates dirham', currencyCode: 'AED', currencySymbol: 'إ.د', id: 'ARE', name: 'United Arab Emirates', dailCode: '971'},
{ currency: 'British pound', currencyCode: 'GBP', currencySymbol: '£', id: 'GBR', name: 'United Kingdom', dailCode: '44'},
{ currency: 'United States dollar', currencyCode: 'USD', currencySymbol: '$', id: 'USA', name: 'United States', dailCode: '1'},
];
const [selectedOption, setSelectedOption] = React.useState();
const { filteredOptions, getSearchInputProps, searchTerm } = useFilteredOptions({
initialOptions: countries,
searchFunction: ({ options, searchTerm }) => {
if (searchTerm === "") return options;
return options.filter((option) => {
const getOnlySearchableKeys = Object.fromEntries(Object.entries(option).filter(([key, index]) =>
key !== 'currencyCode' && key !== 'currency')
);
return Object.values(getOnlySearchableKeys).map((value) =>
value.toLowerCase()
).join(" ").includes(searchTerm.toLowerCase());
})
},
});
React.useLayoutEffect(() => {
const usersCountry = countries.find((country) => country.dailCode === '91');
if (usersCountry) {
setSelectedOption(usersCountry);
}
}, []);
function NoResults() {
return (
<Text className="text-secondary text-center text-body-12 py-4">No matching results</Text>
);
}
function escapeRegExp(string) {
return string.replace(/[+$]/g, '\\$&');
}
function highlightMatchedContent(text, searchTerm) {
if (!searchTerm) return text;
const escapedSearchTerm = escapeRegExp(searchTerm);
const regex = new RegExp(`(${escapedSearchTerm})`, 'gi');
const parts = text.trim().split(regex);
return parts.map((part, index) =>
regex.test(part) ? (
<span className="font-stronger" key={index}>
{part}
</span>
) : (
part
)
);
}
return (
<Field label="Select Country Code" classNames={{ label: 'whitespace-nowrap'}} className="w-20">
<FilterMenu popoverMaxWidth={280} popoverMaxHeight={300}>
<FilterMenuTrigger placeholder="Select Country"
{...(selectedOption
? {
children: `+${selectedOption.dailCode}`,
}
: null)
}
/>
<FilterMenuPopover>
<FilterMenuSearchField label="Search Items">
<FilterMenuSearchInput
{...getSearchInputProps()}
placeholder="Search..."
/>
</FilterMenuSearchField>
<FilterMenuListbox
noResultsFallback={<NoResults />}
options={filteredOptions}
>
{(option) => (
<FilterMenuItem
id={option.id}
isSelected={selectedOption.id === option.id}
onClick={() => {
setSelectedOption(option);
}}
>
<Track
className="gap-1"
classNames={{
center: 'grow-0 line-clamp-1',
}}
railEnd={<>+{highlightMatchedContent(option.dailCode, searchTerm)}</>}
>
{highlightMatchedContent(option.name, searchTerm)}
</Track>
</FilterMenuItem>
)}
</FilterMenuListbox>
</FilterMenuPopover>
</FilterMenu>
</Field>
);
- To get all the currency and country data needed to build this component, check out Business utilities package.
- The
popoverMaxWidth,popoverMaxHeight,popoverPlacement, andpopoverMatchReferenceWidthprops have the same effect on the FilterMenu component as the Dropdown Menu. - To control the size of the Trigger, use the width class on the
<Field>component. - To control the Trigger appearance to "subtle," wrap
<FilterMenu>with Inline Field.
Strategy
Use the strategy prop to change the way how popover element will be positioned. By default, the strategy is set to absolute, changes it to fixed when the FilterMenuTrigger is inside a sticky or fixed element.
This option leverages the floating-ui library, which powers the FilterMenuPopover functionality.
const initialOptions = [
{ code: "61", id: "AUS", name: "Australia" },
{ code: "64", id: "NZL", name: "New Zealand" },
{ code: "91", id: "IND", name: "India" },
{ code: "48", id: "POL", name: "Poland" },
{ code: "44", id: "GBR", name: "Scotland (UK)" },
{ code: "1", id: "USA", name: "United States" },
];
const [selectedOption, setSelectedOption] = React.useState(
initialOptions[0]
);
const [showFixedElement, setShowFixedElement] = React.useState(false);
const onButtonClick = () => {
setShowFixedElement((prevState) => !prevState)
}
const [searchTerm, setSearchTerm] = React.useState('');
function onClear(){
return setSearchTerm('');
}
function handleInputOnChange(event) {
return setSearchTerm(event.target.value);
}
const filteredOptions = searchTerm === "" ? initialOptions : initialOptions.filter((country) =>
country.name.toLowerCase().includes(searchTerm.toLowerCase())
);
function OptionLabel({ name, code }) {
return (
<Track as="span">
{name} +{code}
</Track>
);
}
function NoResults() {
return (
<Text className="text-secondary text-center text-body-12 py-4">
No matching results
</Text>
);
}
return (
<Stack className="w-full gap-4">
{showFixedElement ? (
<div
className="
animate-[snackbar-transition_0.3s_cubic-bezier(0.16,_1,_0.3,_1)]
bg-neutral-secondary
fixed
flex
items-center
justify-between
mx-2
p-4
right-0
rounded-8px
shadow-40
sm:right-8
sm:w-[360px]
top-8
w-[calc(100%-16px)]
z-10
"
>
<Field label="Select Items">
<FilterMenu strategy="fixed">
<FilterMenuTrigger placeholder="Select Country">
{selectedOption ? <OptionLabel {...selectedOption} /> : null}
</FilterMenuTrigger>
<FilterMenuPopover>
<FilterMenuSearchField label="Search Items">
<FilterMenuSearchInput
onClear={onClear}
onChange={handleInputOnChange}
value={searchTerm}
placeholder="Search..."
/>
</FilterMenuSearchField>
<FilterMenuListbox
noResultsFallback={<NoResults />}
options={filteredOptions}
>
{(option) => (
<FilterMenuItem
id={option.id}
isSelected={selectedOption.id === option.id}
onClick={() => {
setSelectedOption(option);
}}
>
<OptionLabel {...option} />
</FilterMenuItem>
)}
</FilterMenuListbox>
</FilterMenuPopover>
</FilterMenu>
</Field>
<button
className="
focus-visible:focus-ring
font-stronger
px-1
py-0.5
rounded-4px
text-body-12
text-primary
underline
underline-offset-2
"
onClick={onButtonClick}
>
Close
</button>
</div>
) : null}
<Button onClick={onButtonClick}>
Show fixed element
</Button>
</Stack>
);
Disabled
Utilize the isDisabled prop in the <Field/> to show that a entire FilterMenu isn't usable.
const initialOptions = [
{ code: "61", id: "AUS", name: "Australia" },
{ code: "64", id: "NZL", name: "New Zealand" },
{ code: "91", id: "IND", name: "India" },
{ code: "48", id: "POL", name: "Poland" },
{ code: "44", id: "GBR", name: "Scotland (UK)" },
{ code: "1", id: "USA", name: "United States" },
];
const [selectedOption, setSelectedOption] = React.useState(
initialOptions[0]
);
const [searchTerm, setSearchTerm] = React.useState('');
function onClear(){
return setSearchTerm('');
}
function handleInputOnChange(event) {
return setSearchTerm(event.target.value);
}
const filteredOptions = searchTerm === "" ? initialOptions : initialOptions.filter((country) =>
country.name.toLowerCase().includes(searchTerm.toLowerCase())
);
function OptionLabel({ name, code }) {
return (
<Track as="span">
{name} +{code}
</Track>
);
}
function NoResults() {
return (
<Text className="text-secondary text-center text-body-12 py-4">
No matching results
</Text>
);
}
return (
<Field label="Select Items" isDisabled>
<FilterMenu>
<FilterMenuTrigger placeholder="Select country">
{selectedOption ? <OptionLabel {...selectedOption} /> : null}
</FilterMenuTrigger>
<FilterMenuPopover>
<FilterMenuSearchField label="Search Items">
<FilterMenuSearchInput
onClear={onClear}
onChange={handleInputOnChange}
value={searchTerm}
placeholder="Search..."
/>
</FilterMenuSearchField>
<FilterMenuListbox
noResultsFallback={<NoResults />}
options={filteredOptions}
>
{(option) => (
<FilterMenuItem
id={option.id}
isSelected={selectedOption.id === option.id}
onClick={() => {
setSelectedOption(option);
}}
>
<OptionLabel {...option} />
</FilterMenuItem>
)}
</FilterMenuListbox>
</FilterMenuPopover>
</FilterMenu>
</Field>
);
Disabled MenuItem
Utilize the isDisabled prop in the <FilterMenuItem /> component to indicate that a specific item is not selectable.
This enhances user experience by clearly displaying the disabled state. Additionally, for improved accessibility, keyboard navigation will bypass disabled MenuItems in the Listbox.
const initialOptions = [
{ code: "61", id: "AUS", name: "Australia", disabled: true},
{ code: "64", id: "NZL", name: "New Zealand", disabled: false},
{ code: "91", id: "IND", name: "India", disabled: false},
{ code: "48", id: "POL", name: "Poland", disabled: true},
{ code: "44", id: "GBR", name: "Scotland (UK)", disabled: false},
{ code: "1", id: "USA", name: "United States", disabled: true},
];
const [selectedOption, setSelectedOption] = React.useState(
initialOptions[0]
);
const [searchTerm, setSearchTerm] = React.useState('');
function onClear(){
return setSearchTerm('');
}
function handleInputOnChange(event) {
return setSearchTerm(event.target.value);
}
const filteredOptions = searchTerm === "" ? initialOptions : initialOptions.filter((country) =>
country.name.toLowerCase().includes(searchTerm.toLowerCase())
);
function OptionLabel({ name, code }) {
return (
<Track as="span">
{name} +{code}
</Track>
);
}
function NoResults() {
return (
<Text className="text-secondary text-center text-body-12 py-4">
No matching results
</Text>
);
}
return (
<Field label="Select Items">
<FilterMenu>
<FilterMenuTrigger>
<OptionLabel {...selectedOption} />
</FilterMenuTrigger>
<FilterMenuPopover>
<FilterMenuSearchField label="Search Items">
<FilterMenuSearchInput
onClear={onClear}
onChange={handleInputOnChange}
value={searchTerm}
placeholder="Search..."
/>
</FilterMenuSearchField>
<FilterMenuListbox
noResultsFallback={<NoResults />}
options={filteredOptions}
>
{(option) => (
<FilterMenuItem
id={option.id}
isDisabled={option.disabled}
isSelected={selectedOption.id === option.id}
onClick={() => {
setSelectedOption(option);
}}
>
<OptionLabel {...option} />
</FilterMenuItem>
)}
</FilterMenuListbox>
</FilterMenuPopover>
</FilterMenu>
</Field>
);
Note: Disabled item can already be selected option but having any interactions on it won't be possible.
FullScreen on Mobile
On mobile, enable fullScreenForMobile to render the sheet in full-screen with a default close button.\
const initialOptions = [
{ id: "1", value: "Item 1" },
{ id: "2", value: "Item 2" },
{ id: "3", value: "Item 3" },
];
const [selectedOption, setSelectedOption] = React.useState(initialOptions[0]);
const { filteredOptions, getSearchInputProps } = useFilteredOptions({
initialOptions,
searchFunction: ({ options, searchTerm }) => {
if (searchTerm === "") return options;
return options.filter((option) =>
option.value.toLowerCase().includes(searchTerm.toLowerCase())
);
},
});
return (
<Field label="Select Items">
<FilterMenu fullScreenForMobile>
<FilterMenuTrigger placeholder="Select">
{selectedOption.value}
</FilterMenuTrigger>
<FilterMenuPopover>
<FilterMenuSearchField label="Search Items">
<FilterMenuSearchInput
{...getSearchInputProps()}
placeholder="Search..."
/>
</FilterMenuSearchField>
<FilterMenuListbox
noResultsFallback={
<Text className="text-secondary text-center text-body-12 py-4">
No matching results
</Text>
}
options={filteredOptions}
>
{(option) => (
<FilterMenuItem
id={option.id}
isSelected={selectedOption.id === option.id}
onClick={() => {
setSelectedOption(option);
}}
>
{option.value}
</FilterMenuItem>
)}
</FilterMenuListbox>
</FilterMenuPopover>
</FilterMenu>
</Field>
);
API Reference
FilterMenu
| Props | Type | Description | Default |
|---|---|---|---|
children | ((menuState: { isMenuOpen: boolean; triggerProps: TriggerProps }) => ReactNode) | ReactNode | Accepts either a React node or a render function. The render function provides the menu's state (isMenuOpen) and accessibility/interaction props (triggerProps) for the trigger. | _ |
closeButtonPropsForMobile? | { label: string, onClick: () => void, size?: IconButtonProps['size'] } | Props for the close button that appears on mobile. | _ |
mobileFriendly? | boolean | Indicates whether the filter menu should be displayed as a sheet on mobile devices. | true |
popoverMatchReferenceWidth? | boolean | Match the width of the popover with the reference element. | false |
popoverMaxHeight? | number | The max height of the filter menu popover. | 356 |
popoverMaxWidth? | number | The max width of the filter menu popover. | 400 |
popoverOffset? | number | The offset of the filter menu popover. | 4 |
popoverPlacement? | 'bottom' | 'bottom-start' | 'bottom-end' | The placement of the filter menu popover in relation to the trigger. | 'bottom-start' |
strategy? | 'absolute' | 'fixed' | The strategy used to position the floating element. | 'absolute' |
titleForMobile? | string | If titleForMobile is provided then the mobile sheet view will have a header with title rendered | _ |
fullScreenForMobile | boolean | Enables fullscreen mode for the mobile select menu, making it cover the entire viewport. | false |
FilterMenuTrigger
The FilterMenuTrigger component is a customizable trigger for a filter menu, built using the Button component. It inherits some Button props and adds few more additional functionalities.
| Prop | Type | Description | Default |
|---|---|---|---|
children? | ReactNode | The content to be displayed inside the button. | _ |
form? | string | Specifies the form element the button is associated with. | _ |
iconEnd? | ReactNode | The icon to display after the button children. | _ |
iconStart? | ReactNode | The icon to display before the button children. | _ |
isLoading? | boolean | If true, the button will display a loading indicator. | false |
isPressed? | boolean | If true, the button will be visually styled as pressed and the aria-pressed attribute will be set accordingly. | false |
loadingLabel? | string | Text to read out to assistive technologies when button is loading. | _ |
onBlur? | function | Function to call when the button loses focus. | _ |
onFocus? | function | Function to invoke when the button receives focus. | _ |
onKeyDown? | function | Function to invoke when a key is pressed while the button is focused. | _ |
placeholder? | string | Displays a placeholder text when no children is provided. | _ |
FilterMenuSearchField
The FilterMenuSearchField internally uses Field component. It inherits most of the Field props and adds few more functionalities.
| Prop | Type | Description | Default |
|---|---|---|---|
children | ReactNode | The content to be displayed inside the field. | _ |
label | ReactNode | Label for the input. | _ |
controlId? | string | Specifies the unique identifier for the form control within the component. See Field API for more details. | _ |
counter? | string | Counter object containing maxValue and value. "maxValue:" maximum value the counter can reach. "value:" current value of the counter. | _ |
description? | ReactNode | Provide additional information that will aid user input. | _ |
errorMessage? | ReactNode | Message to show when the field is invalid. | _ |
isDisabled? | boolean | Whether the field is disabled. | false |
isRequired? | boolean | Whether user input is required on the field. | false |
labelVisibility? | 'visible' | 'hidden' | A label must always be provided for assistive technology, but you may hide it from sighted users when the intent can be inferred from context. | 'hidden' |
secondaryLabel? | ReactNode | Additional context, typically used to indicate that the field is optional. | _ |
FilterMenuSearchInput
The FilterMenuSearchInput component internally uses SearchInput component. It inherits most of the SearchInput props and adds few more functionalities.
| Prop | Type | Description | Default |
|---|---|---|---|
aria-activedescendant? | string | identifies the currently active element when using ARIA widgets. | _ |
aria-autocomplete? | 'inline' | 'list' | 'both' | 'none' | Indicates whether input completion suggestions are provided, and their type. | _ |
aria-controls? | string | Identifies the element(s) that the input controls. | _ |
aria-expanded? | boolean | Indicates whether the popover is currently expanded or collapsed. | _ |
aria-haspopup? | 'dialog' | 'grid' | 'listbox' | 'menu' | 'tree' | 'boolean' | Indicates the availability of a popup related to the input. | _ |
autoComplete? | string | Specifies whether autocomplete is enabled for the input. | _ |
autoCorrect? | 'on' | 'off' | Specifies whether auto-correction is enabled for the input. | _ |
autoFocus? | boolean | Automatically focuses the input element when it is rendered. | _ |
defaultValue? | string | Specifies the initial value of the input for uncontrolled input. | _ |
focusContainerRef? | React.Ref<HTMLDivElement> | Reference to the wrapper FocusContainer element. | _ |
inputMode? | 'none' | 'text' | 'tel' | 'url' | 'email' | 'numeric' | 'decimal' | 'search' | Hints to browsers about what kind of virtual keyboard to display. | _ |
name? | string | Name of the input, used for form submissions. | _ |
onBlur? | function | Function to be invoked when the input loses focus. | _ |
onChange? | function | Function to be invoked when a new item is selected. | _ |
onFocus? | function | Function to be invoked when the input is focused. | _ |
onKeyDown? | function | Function to be invoked when a key is pressed while the input is focused. | _ |
onPaste? | function | Function to be invoked when content is pasted into the input. | _ |
pattern? | string | Regular expression pattern the input's value must match for validation. | _ |
placeholder? | string | Placeholder text displayed when the input is empty. | _ |
role? | string | ARIA role for the input. | _ |
spellCheck? | boolean | Specifies whether the input value should be checked for spelling errors. | _ |
type? | 'email' | 'password' | 'search' | 'tel' | 'text' | 'url' | Type of the input element. | _ |
value? | string | Specifies the current value for controlled inputs. | _ |
FilterMenuPopover
| Prop | Type | Description | Default |
|---|---|---|---|
children | ReactNode | Content of the filter menu popover. | _ |
shouldUsePortal? | boolean | Determines whether the popover should be rendered in a React Portal. If true, the popover will be rendered outside the DOM hierarchy of the parent component. | true |
FilterMenuListbox
| Prop | Type | Description | Default |
|---|---|---|---|
noResultsFallback? | ReactNode | Component to render when there are no options left in the filtered result. | _ |
options? | Array of Objects. | Options to be rendered in the popover. Note: Each item in the object should have unique id of key property for better caching of children | _ |
FilterMenuItem
| Props | Type | Description | Default |
|---|---|---|---|
children | ReactNode | The content of the filter menu item. | _ |
id? | string | An optional ID for the menu item. If not provided, an ID will be automatically generated. | _ |
isDisabled? | boolean | Indicates if the menu item is currently disabled. Used for styling and accessibility. Applies an aria-disabled attribute. | false |
isHighlighted? | boolean | Indicates if the menu item is currently highlighted. Used for styling. Applies a data-highlighted attribute. Note: Controlled internally to support keyboard navigations. | false |
isSelected? | boolean | Indicates if the menu item is currently selected. Used for styling. Applies an aria-selected=true and data-selected=true otherwise aria-selected=false | false |
onClick? | () => boolean | void | Function to be invoked when the item is clicked. | _ |
railEnd? | ReactNode | The content/components to appear in the item end. | _ |
railStart? | ReactNode | The content/components to appear in the item start. | _ |
showSelectionIndicator? | boolean | Controls whether to show the selection indicator (check icon) for selected items. | true |
size? | 'standard' | 'large' | The size of the filter menu item. | 'standard' |
verticalAlign? | 'bottom' | 'middle' | 'top' | Determines how the rails and center are vertically aligned to each other. A typography or heading can be provided to center align icons and with text that may wrap. | 'middle' |
Style API
Our design system components include style props that allow you to easily customize different parts of each component to match your design needs.
Please refer to the Style API documentation for more insights.