# Filter menu

A component used to apply category-specific filters for a dataset.

Tabs: [Guidelines](/components/web/filter-menu/filter-menu.guidelines.md) · [Code](/components/web/filter-menu/filter-menu.code.md)

## Features

- Flexible and composable API.

- Unopinionated about form elements within the filter menu.

- Display a "count" for the number of applied filters.

- Provides a companion component for grouping filter toggles.

## When to use

See our [filtering guidelines](/patterns/filtering/filtering.about) to learn why and when you should use this component.

## Examples

### Complete example

We only provide presentational components for filtering, so you'll need to:

- Keep track of interim filters.
- Apply filters (and fetch data) when appropriate.
- Indicate that filters are applied.
- Enable "Clear" and "Apply" actions when applicable.
- Persist applied filters in the URL.

> Please refer to our [Filtering guidelines](/patterns/filtering/filtering.about) for more details.

```tsx
const initialFilters = {a: false, b: false}
const Example = () => {
    const [interimFilters, setInterimFilters] = React.useState(initialFilters)
    const [appliedFilters, setAppliedFilters] = React.useState(initialFilters)

    const onToggleFilter = (name) =>
        setInterimFilters({...interimFilters, [name]: !interimFilters[name]})
    const onClose = () => setAppliedFilters(interimFilters)
    const onClearFilters = () => setInterimFilters(initialFilters)

    const numAppliedFilters = Object.values(appliedFilters).filter((item) => !!item).length

    return (
        <FilterMenu onClose={onClose}>
            <FilterMenu.Trigger>
                <FilterMenu.Toggle
                    numAppliedFilters={numAppliedFilters}
                    hasAppliedFilters={!isEqual(initialFilters, appliedFilters)}
                >
                    Status
                </FilterMenu.Toggle>
            </FilterMenu.Trigger>
            <FilterMenu.Content>
                <Stack p={20} space={10}>
                    <Checkbox checked={interimFilters.a} onChange={() => onToggleFilter('a')}>
                        Ready for payment
                    </Checkbox>
                    <Checkbox checked={interimFilters.b} onChange={() => onToggleFilter('b')}>
                        Awaiting approval
                    </Checkbox>
                </Stack>
                <FilterMenu.Actions>
                    <FilterMenu.Apply disabled={isEqual(interimFilters, appliedFilters)}>
                        Apply
                    </FilterMenu.Apply>
                    <FilterMenu.Clear
                        disabled={isEqual(initialFilters, interimFilters)}
                        onClick={onClearFilters}
                    >
                        Clear
                    </FilterMenu.Clear>
                </FilterMenu.Actions>
            </FilterMenu.Content>
        </FilterMenu>
    )
}

render(<Example />)
```

### Grouped example

```tsx
const initialFilters = {a: false, b: false}
const GroupedExample = () => {
    const [interimFilters, setInterimFilters] = React.useState(initialFilters)
    const [appliedFilters, setAppliedFilters] = React.useState(initialFilters)

    const onToggleFilter = (name) =>
        setInterimFilters({...interimFilters, [name]: !interimFilters[name]})
    const onClose = () => setAppliedFilters(interimFilters)
    const onClearFilters = () => setInterimFilters(initialFilters)
    const onSelectAll = () => setInterimFilters({a: true, b: true})

    const numAppliedFilters = Object.values(appliedFilters).filter((item) => !!item).length
    const isAllSelected = Object.values(interimFilters).every((item) => item)

    return (
        <FilterMenu onClose={onClose}>
            <FilterMenu.Trigger>
                <FilterMenu.Toggle
                    numAppliedFilters={numAppliedFilters}
                    hasAppliedFilters={!isEqual(initialFilters, appliedFilters)}
                >
                    Status
                </FilterMenu.Toggle>
            </FilterMenu.Trigger>
            <FilterMenu.Content>
                <Stack p={20} space={10}>
                    <Checkbox checked={interimFilters.a} onChange={() => onToggleFilter('a')}>
                        Ready for payment
                    </Checkbox>
                    <Checkbox checked={interimFilters.b} onChange={() => onToggleFilter('b')}>
                        Awaiting approval
                    </Checkbox>
                </Stack>
                <FilterMenu.Actions>
                    <FilterMenu.Apply disabled={isEqual(interimFilters, appliedFilters)}>
                        Apply
                    </FilterMenu.Apply>
                    <FilterMenu.ActionsGroup>
                        <FilterMenu.Clear
                            disabled={isEqual(initialFilters, interimFilters)}
                            onClick={onClearFilters}
                        >
                            Clear
                        </FilterMenu.Clear>
                        <FilterMenu.Button disabled={isAllSelected} onClick={onSelectAll}>
                            Select all
                        </FilterMenu.Button>
                    </FilterMenu.ActionsGroup>
                </FilterMenu.Actions>
            </FilterMenu.Content>
        </FilterMenu>
    )
}

render(<GroupedExample />)
```

### Specific layout for grouping filters

The Toggle component supports a `moreFilters` prop that will display a chevron on the right-hand side. Use it when you need to group multiple filtering options within the same filter menu. See our [Filtering layout guidelines](/patterns/filtering/filtering.about#ordering-and-layout) for more details.

```tsx
<FilterMenu>
    <FilterMenu.Trigger>
        <FilterMenu.Toggle moreFilters>More filters</FilterMenu.Toggle>
    </FilterMenu.Trigger>
</FilterMenu>
```

### Toggle loading state

Toggle component supports loading state via `loading` prop. Use it when applied filters are being fetched. See our [Filtering guidelines](/patterns/filtering/filtering.about#loading) for more details.

```tsx
<FilterMenu>
    <FilterMenu.Trigger>
        <FilterMenu.Toggle loading>Category</FilterMenu.Toggle>
    </FilterMenu.Trigger>
</FilterMenu>
```

### Trigger element skeleton state

Use a "skeleton" version of this component to display a loading state while data is being fetched. It provides a visual placeholder, giving users a preview of the UI structure before the actual content is loaded. This enhances the user experience by offering a more accurate representation of the final layout during data retrieval.

```tsx
<FilterMenu>
    <FilterMenu.Trigger>
        <FilterMenu.Toggle skeleton>Category</FilterMenu.Toggle>
    </FilterMenu.Trigger>
</FilterMenu>
```

## Related components

- [Filter results](/components/web/filter-results/filter-results.guidelines): Used to reflect the amount of results given a set of applied filters. It's also used to allow users to clear all filters.
- [Listbox](/components/web/listbox/listbox.guidelines): A listbox provides a way to select or reorder options in a predefined list and a selected option can then be made to perform a single action.
- [Popover](/components/web/popover/popover.guidelines): A small overlay that opens on demand. Popovers allow users to access additional content and actions without cluttering the page.
