SegmentedButton
An interactive element where users choose an action in a set of related buttons.
The Basics
What it is
SegmentedButton is an interactive element that enables users to take complex button actions. It can allow users to select and deselect multiple options from a group of buttons, like List; or select a single option from 2+ mutually exclusive options, like RadioGroup; or choose from a set of related actions at the same level of emphasis. If SegmentedButton has a Menu in it, the dropdown menu displays secondary actions.
How it works
- SegmentedButton can act as a radio button, clearable radio button, a checkbox button, traditional button, or a Split-primary button.
- For radio style SegmentedButtons:
- The user clicks or activates an option’s button in SegmentedButton, which selects the option and makes it active. The button style changes to selected.
- The user can deselect the option by activating another option. The deselected button changes back to its default style.
- Once the user interacts with SegmentedButton, an option will remain selected, but in clearable radio style SegmentedButtons, the component can be reset to an unselected state by clicking on the button segment again.
- For checkbox style SegmentedButtons:
- The user clicks or activates an option’s button in SegmentedButton, which selects the option and makes it active. The button style changes to selected.
The user can deselect an option by clicking or activating the same button again. The button changes back to its default style.
The user’s selections usually aren’t saved until they take another action, like using a button (“Submit”).
- The user clicks or activates an option’s button in SegmentedButton, which selects the option and makes it active. The button style changes to selected.
- For button style SegmentedButtons:
- The user clicks or activates a button in SegmentedButton, which triggers an action.
- If SegmentedButton has a Menu in it, the dropdown menu displays secondary actions. These items should work like the buttons in the main button row: when clicked or activated, they trigger an action.
- For split-primary style SegmentedButtons:
- There are only two button segments.
- The user clicks or activates the primary (left) button in SegmentedButton, which triggers an action.
- The right button has Menu in it, the dropdown menu displays additional actions. These items should work like the primary button: when clicked or activated, they trigger an action.
When to use
- To ask users to select a single option while saving vertical space
- To ask users to select one or more options in a horizontal layout
- To group related actions in a single, compact element
- To provide a more tappable user experience on mobile devices
- To set filters or select a value or values from a list of options
- For lists of options that are up to 3 words long
- To display a primary action and “hide” secondary, related actions in a menu
When not to use
- For lists of options that are more than 3 words long
- For lists with so many options that users need to filter them
What to use instead
Use Button for multiple unrelated action buttons.
Use RadioGroup to display options as a list
Use a selection style List for a list with checkboxes to select options
Use ToggleSwitch for instant on/off states.
Use Select for filtering long lists
How to use
Use radio function SegmentedButton to set filters or select values from a set of options. Its button form makes it more visual and tappable, but behind the scenes, it works like RadioGroup.
Use checkbox function SegmentedButton to set filters or select values from a list of options. Its button form is more visual and tappable, but behind the scenes, it works like List.
Use button style SegmentedButton when you have a set of buttons for related actions that should be grouped together, like buttons for related document actions (Download, Share, Print), instead of spread out. By visually grouping these actions in the same element, SegmentedButton shows that they’re related, while saving horizontal space.
Use split-primary style SegmentedButton when you have a single primary action, and a set of related actions that should be grouped in a menu.
Group related actions in the same SegmentedButton.
Group unrelated functions or actions.
Use SegmentedButton with a Menu in it when there’s a primary action and related, secondary options that are used less frequently (like a Save button with a dropdown that contains options to “Save & Print” and “Save & Close”).
Default Selection
In most cases, radio style SegmentedButton shouldn’t have an option selected by default. This is especially important in healthcare contexts. After the data is saved, it may not be clear if the user actively selected an option or forgot to answer and left the default selected. This can lead to problems with data integrity and even patient safety. For example, if “No known allergies” is selected by default, this could be saved incorrectly in the patient’s chart, potentially endangering the patient in the future.
Undoing a selection
Once a user selects a radio option, it will remain selected unless a different option is selected. In clearable radios, selecting the option again resets the component to an unselected state.
Style
Design details
The SegmentedButton group consists of 2+ buttons that are displayed horizontally by default. When displayed horizontally, SegmentedButton can be aligned as a connected or separated group. On screens smaller than 640px, they automatically stack vertically and span the width of their container.
Size
SegmentedButton is available in four sizes:
- Small (22px H)
- Medium (28px H)
- Large (32px H)
- Extra Large (56px H)
Icons are only available in Large and Extra Large SegmentedButtons.
Placement and hierarchy
No additional information for this component.
Content
For all styles of SegmentedButton, use sentence case for button text (“All appointments”, not “all appointments” or “All Appointments”).
When used as a group of related buttons, SegmentedButton is designed to trigger actions, so use verbs for button text, not adjectives. Keep it short (1-2 words) to avoid wrapping and use title case (“Save File”, not “Save file”).
When using the icon-only version of SegmentedButton, make sure the meaning of the icon is clear without any text. The Icons guidelines page lists all Forge icons, their usage, and whether a label is required.
When using SegmentedButton with a Menu in it, the button that opens the menu should include the Expand icon and/or explanatory copy, like “More Actions”, “See More”, or “Other”. Use title case for menu text (“More Options”, not “More options”). In the case of split-primary, there is only an expand chevron and no text in the right-hand segment.
Demos
Coding
Developer tips
SegmentedButton takes React elements as its children; these should be Button and/or Menu components. For documentation, see the SegmentedButton props table and the Menu component page.
SegmentedButton is a wrapper element used to coordinate styling of its Button or Menu children. This styling also prevents the internal corners of buttons from rounding over when placed directly side by side.
To customize individual segments of a SegmentedButton see the Button props table for the Button component. For example, disabling a single option can be done by adding the 'disabled' prop from Button to an individual segment.
###Behavior
SegmentedButton is a generic component, where the generic parameter affects
the type of the value
and onChange
props. If behavior="radio"
, then value
and the event.target.value
parameter passed to onChange
can be strings.
Otherwise they are string[]
.
To get split-primary styling, there are no specific props to set other than alignment="connected" behavior="button"
, which are the defaults.
Instead, split-primary styling is automatically applied when the first child is a <Button>
and the second child is a <Menu trigger={<Button />}
. If the menu trigger Button has any text, then
split primary styling is not applied.
Repository
Implementation links
SegmentedButton 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.
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 { SegmentedButton } 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 SegmentedButton from '@athena/forge/SegmentedButton';
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 SegmentedButton from '@athena/forge/dist/SegmentedButton';