BalanceReckon Design System
Overlays

Select Menu

The single select is used for setting enumerable values when filtering data.

import { SelectMenu, FilterMenu, stateChangeTypes, SelectMenuButton, toggleArrayValue } from '@balance-web/select-menu';
Loading demo…

The SelectMenu shares most of its behaviour, appearance and API with the DropdownMenu. Rather than accepting children you must provide options as an array, an onChange handler and a value.

Standard

Single select

Loading demo…

Multi select

The SelectMenu is unopinionated in how many items are selected in the list, or how you manage selected options. Pass an array to the value prop to select more items. Options in a multi select render a checkbox instead of a tick, and in a FilterMenu the search text stays after each pick. When the screen controls inputValue, the screen decides when to clear it.

Loading demo…

Select all

Every multi select shows a "Select all" checkbox row above the options. Pass onSelectAll to handle it, or hideSelectAll to opt out; the types require one of the two when value is an array. The checkbox is empty when none of the shown options are selected, partly selected when some are, and checked when all are. Choosing it selects every shown option, or clears them when all are already selected. In a FilterMenu, the shown options are the ones that match the search; disabled options and selected options that are not shown are left as they are. onSelectAll is called with the whole next value.

Loading demo…

Disabled option

You may disable options where appropriate.

Loading demo…

Filterable

The FilterMenu shares most of the SelectMenu API, with a few additions to manage filtering -- checkout the SelectMenu docs to learn more.

Loading demo…

Async

The FilterMenu has no opinions about how you filter the options, whether it's client or server side. If you fetch options onInputChange, you must show the user that it isLoading. We recommend using debounce (or similar) to optimise performance.

Loading demo…

Advanced

Use the footerOption prop to pin a special action item at the bottom of the menu, separated by a divider. The footer item is always visible regardless of scroll position. Use itemRenderer to render it differently from regular options — typically as a TextLinkButton or similar call-to-action.

NOTE: Inside itemRenderer, check the item's value to distinguish the footer item from regular options and return the appropriate element.

Loading demo…

Group labels and dividers

A menu has no nested groups. To show group labels, dividers or other rows that are not options, insert them into options and return false for them from itemToSelectable. SelectMenu and FilterMenu render those rows with itemRenderer, without a checkbox or tick and without padding, so the content controls its own layout. The keyboard skips them, they can't be clicked or chosen, and "Select all" leaves them out.

  • Give every row a unique value from itemToValue; it is the row's React key.
  • itemHeight receives the row's index in options ("Select all" doesn't count), so return a smaller height for labels and dividers.
  • In a FilterMenu, filter the groups before flattening them into options, so a label is never left without options under it.
Loading demo…

Recipes

Mapping

Provide alternative properties in your options using the itemToDisabled, itemToValue, and itemToLabel utilities. Map complex objects to the required data select-menu requires while using other properties in the itemRenderer.

Loading demo…

Item renderer

You can provide an alternate item renderer.

Loading demo…

itemHeight

Used in conjunction with itemRenderer to achieve custom layouts.

Default is 40

By default, the menu dialog will match the width of the input container. For situations where horizontal real estate is limited this might mean that menu items are clipped. Provide a menuWidth prop to resolve the issue, accomodating expected item label lengths.

Loading demo…

Clearable value

Provide onClear in addition to the onChange handler to let the user clear all the values with one click.

Loading demo…

Labelling

There's a few strategies for displaying the value within the button.

selectedValueThreshold

The most user friendly approach is to display as much information as possible to the user within your space constraints. In the example below we show up to 2 values, then when there's more than two we show the first selected value and the remaining count.

Loading demo…

Indicator

When horizontal space is at a premium you may want to display the count in a notification badge.

Loading demo…

Custom trigger button

SelectMenuButton is the chip-styled button SelectMenu/FilterMenu render internally as their default trigger — reach for it directly when you need a trigger that looks native but with custom content, rather than passing a function to trigger.

Loading demo…

stateChangeTypes

stateChangeTypes re-exports downshift's useCombobox.stateChangeTypes — the set of action-type constants downshift uses internally (InputKeyDownEnter, ItemClick, …). Reach for it when you need to distinguish how a selection was made, for example inside a custom onLoadMore/onIsOpenChange handler for an embedded grid cell editor.

Pagination

SelectMenu can be used in a paginated mode using the infinite scrolling technique.

To use pagination you must provied the following props:

  • canLoadMore — signal that more items are available
  • onLoadMore — function to load more items when user reaches the bottom of the menu and canLoadMore is true
  • loadingState — must be kept in-sync to avoid duplicate calls

NOTE: Like all handlers, onLoadMore must be memoized with React.useCallback() for performance.

Loading demo…

On this page