HighVolumeMultiSelect
A MultiSelect variant that allows users to view a list of selections for high volumes of data.
The Basics
What it is
High Volume MultiSelect is a component that enables users to enter data by selecting 1+ options from a predefined list with a high volume of options or selections.
High Volume MultiSelect differs from traditional select by enabling users to better select inputs from very large volumes of inputs with varied results. When multiple selections are made, the right-hand panel visually tracks selections and allows users to scroll through completed selections while they search for additional selections. As well, the "Select All" and "Clear All" options allow users to start with everything selected and define what is unselected in a similar fashion.
How it works
- The user is presented with a dual panel layout.
- The left panel lists all options (available or disabled), with a checkbox associated with each item.
- The right panel lists all selected options, each displayed as a Forge Tag.
- Users can select available options from the left panel by clicking the associated checkbox, thus adding the item to the right panel; those options can then be deselected—or removed—by clicking the Remove icon on the given Tag.
- Once an option is selected, its associated checkbox remains active, or "checked", in the left panel. It can be deselected with a click, removing it from the right panel
- Users can perform bulk actions by clicking the "Select All" button or "Clear All" button in the left and right panels, respectively.
- Clear All
- The "Clear All" button will remain disabled until at least one option is selected and populating the right panel. When clicked, all options will be deselected in the left panel and the right panel will be cleared. Reverting the "Clear All" button to its disabled state.
- Select All
- Insofar as at least one option is not selected, the "Select All" button will be active.
- If clicked, all available options in the left panel will be checked with Tags added to the right panel accordingly. The "Select All' checkbox will then be disabled.
- If all options are selected, the "Select All" button will be disabled.
- Clear All
- The left panel contains a Forge Input field. Typing in that field algorithmically filters the list of options presented in the left panel.
- If the text filters out all options, the left panel will render text indicating empty state.
- The state of selections does not clear if the user navigates away.
When to use
- When the user will need to make a high volume of selections in a Select.
- When the user will need to select from a high volume of options in a Select.
When not to use
- If the user is unlikely to make more than 7 selections.
- If the user is unlikely to need to select from more than 7 options.
- In designs with space constraints.
What to use instead
Use the standard MultiSelect if the user is not likely to make more than 7 selections.
How to use
HighVolumeMultiSelect can be utilized as a stand alone component or within a form just as MultiSelect is used. However, High Volume MultiSelect does not have built in support for async operations.
Filtering the options list
Typing in the field automatically displays a filtered list of options that match the input. This helps users find specific options in long lists (e.g., typing “hyper” to narrow down a long list of diagnoses).
The filtering function compares the input to the text and value for every option in the list and displays the matches. For example, if an option's text is “Tylenol” and its value is “acetaminophen”, then the input “ace” is a match. If the input doesn't match anything in the list, “No options found” appears below the field.
Loading the options list
The dropdown options list can only be loaded synchronously.
- Synchronous (on page load)
- Used for predefined lists that don’t change often.
- Loads at the same time as the rest of the page, so that when the component is activated, it displays the full list of options immediately.
- As users start typing in the field, matches appear instantly.
Style
Design details
Required fields
This component has an optional attention bar to indicated required fields. See Form for details about how to use required states.
Placement and hierarchy
No additional information for this component.
Content
The component is flexible, accepting both strings and objects for the options prop contents. Despite this flexibility, the display format for checkbox labels is uniformly “text [value]”.
There’s no maximum length for option text.
Demos
Coding
Developer tips
Event Handling:
Not all user interactions trigger event props. For instance, search functionality is internal and doesn’t emit events. Custom event handlers have been implemented for specific interactions affecting selected/unselected states. These handlers are designed to receive both the event and the affected option keys, overcoming the limitations of DOM events in providing this data. The setKeys prop simplifies state management, although it's not a conventional change event.
ID Requirement:
The component mandates unique IDs due to the design of the Checkbox component in the Forge library. This requirement is a direct adaptation from the Checkbox's unique specifications.
Internal Options Representation:
The options prop undergoes transformation into an internal format, which includes information about disabled and selected states. This centralized approach requires regular recalculations during user interactions. We maintain performance with large datasets through the Virtuoso library’s virtualization capabilities.
useEffect Hooks:
The component utilizes two main useEffect hooks. The first processes changes in the options prop into our structured format, while the second manages updates to the selected state, differing based on control mode.
Asynchronous Options and Virtualization:
Asynchronous options are not currently supported for simplicity. For handling large datasets, we chose the Virtuoso library for virtualization after evaluating several alternatives. However, if the consumer wants something like a spinner on only the left side to show options populating, this shouldn’t be too heavy a lift as long as the spinner is surrounding the virtuoso container.
Repository
Implementation links
HighVolumeMultiSelect directory in Bitbucket
Implementation details
It is strongly recommended to familiarize yourself with the Forge source code. While this documentation is a best effort to document the intent and usage of a component, sometimes some features only become clear when looking at the source code. Also, looking at Forge's source code may help identify and fix bugs in either your application or Forge itself.
Storybook files
Forge maintains at least one storybook file per component. While the primary audience for these files is typically the Forge team, these storybook files may cover usages of the component not covered by a demo. The storybook for the latest version of forge can be found at go/forge-storybook-lts.
Testing library
Forge strongly encourages using testing-library to write tests for your application.
"The more your tests resemble the way your software is used, the more confidence they can give you."
If you're having trouble testing a Forge component using testing-library, it would be a good idea to see how Forge tests its own components. For the most part, Forge tries to use screen.getByRole as much as it can, as that API provides the best feedback on a11y compliance. Forge discourages the use of document.querySelector and screen.getByTestId as both APIs encourage using implementation details to test your component, and discourage adding roles to your component.
With that being said, many of Forge's components were not built with accessibility in mind. These components do break the recommendations listed above.
Import statements
In Nimbus applications
athenaOne serves the Forge bundle independently from your application's bundle. Importing Forge components directly from '@athena/forge'
takes advantage of this feature.
import { HighVolumeMultiSelect } from '@athena/forge'
In standalone applications
Importing components using the exact path to the module takes advantage of webpack's tree shaking feature. Webpack will include only that module and its dependencies.
import HighVolumeMultiSelect from '@athena/forge/HighVolumeMultiSelect';
To use this import guidance, Typescript applications must use typescript >= 4.7.3
, and should add this setting to their tsconfig.json file:
{"compilerOptions": {"moduleResolution": "Node16",}}
If this setting doesn't work for your application, use this import statement instead:
import HighVolumeMultiSelect from '@athena/forge/dist/HighVolumeMultiSelect';