The Basics

What it is

Menu enables users to select an action or value from a predefined list. It’s opened by clicking a separate trigger element, and it can contain titles, icons, and dividers.

How it works

  • The user triggers Menu by clicking an element on the page, usually another Forge component like ComboButton, Button, or MenuTrigger (see Demos for an example of MenuTrigger).
  • Menu opens below the trigger element, displaying the actions or values as Menu items.
  • When the user hovers over a Menu item, the Menu item is highlighted.
  • When the user clicks the Menu item, the action is triggered or the value is applied.
  • To close Menu without selecting an option, the user can click anywhere outside the dropdown.

When to use

  • To ask users to select an action or value from a list, like navigation links or filter values

When not to use

  • For a short list of actions or values that can appear directly on the page, reducing the number of clicks
  • For a long list of actions or values (e.g., a list of all possible actions) that would be difficult to navigate in a dropdown

What to use instead

SegmentedButton

Use SegmentedButton for short lists of related actions (can contain Menu).

Button

Use Button for single or unrelated actions.

Select

Use Select to ask users to select an option in a form.

How to use

Using Menu for navigation

Menu can be used to list navigation options, like links that open different web pages or jump to sections of the current page. Navigation elements in the page header or footer often trigger Menu.

If your Menu includes links to both other athenaOne pages and other websites (like reference websites for diagnosis codes), make sure that users can tell the difference between internal athenaOne links and external links. Consider displaying external links as a group, with a divider and title for visual separation.

Using Menu for actions or values

Menu items can be:

  • Actions like Download, Share, and Print
  • Values that trigger actions, like sort order options: A to Z, Most Popular, and Oldest First

Menu is often used to display options that are relevant in the given web page or to a specific element. For example, on a page that shows an imaging report, Menu might be used to display the actions that users can take on that report (Print, Email, Annotate).

If Menu items are actions, make sure that none of them are primary actions or are required to complete the workflow, because users can’t see these actions unless they trigger the Menu.

Titles and dividers

Menu can include non-clickable titles and dividers to help label and group the Menu items. This is helpful for clustering related items (like editing options and sharing options) and separating actions that you don’t want users to click accidentally (like Delete).

Style

Design details

Menu is a small rectangular popover that displays a list of Menu items (text only or text with icons). Non-clickable titles and dividers help label and group items visually.

Menu opens below the trigger element, with its left side aligned with the left side of the trigger. There’s no vertical space between Menu and its trigger. Menu overlays and obscures any content below the trigger.

Placement and hierarchy

No additional information for this component.

Content

Trigger element

If Menu is triggered by an element with visible text (such as SegmentedButton, Button, or MenuTrigger – see Demos for an example of MenuTrigger), use title case for this text (“More Options”, not “More options”).

Label

Menu has a label, which is separate from any text in the trigger element.

  • Displaying the label is optional. It appears above the trigger element.
  • Even if you don’t display the label, it’s still required for accessibility reasons. Include label text in your design so developers can implement it in the code.

The label should complement the trigger element and describe the Menu content:

  • Trigger element text is “Jump to page...”, and label text is “Navigation”.
  • Trigger element text is “Select Filter”, and label text is “Filter Options”.

Menu items

If the Menu items represent:

  • Actions, their text should convey what will happen when users select the item
  • Values, their text should be the name of the value

Use title case for Menu item text (“Print File”, not “Print file”). Keep it short: item text doesn’t wrap or truncate automatically, so a very long Menu item could expand the Menu’s width past the edge of the window. Menu item text can include formatting and styling.

Menu items can include an icon to the left of the text. Make sure to use Forge icons according to their prescribed usage. If using icons, apply them to all Menu items in the list (or section, if you’re using dividers).

Do:

If using icons, apply them to all Menu items in the list or section.

<p>If using icons, apply them to all Menu items in the list or section.</p>
Don't:

Apply icons to just some of the Menu items in the list or section.

<p>Apply icons to just some of the Menu items in the list or section.</p>

Demos

Menu Basic Share

Controlled Share

Menu Using Tertiary Button Share

Coding

Developer tips

Menu trigger element

Menu can be triggered by any element that can be clicked, like a link, ComboButton, Button, or other Forge component. Set the code for this element as the value for Menu’s trigger prop. Clicking the element opens the Menu, and clicking anywhere outside the expanded Menu hides the Menu again.

A typical trigger is the subcomponent MenuTrigger (see Props tables), which is implemented by LabelButton (documented in ComboButton’s Props tables) but with special class names passed on to it. See the Demos for an example of how to use MenuTrigger.

Known issue

Menu’s size prop overrides the size prop of any component passed in by Menu’s trigger prop.

Menu items

Each item in the dropdown is a MenuItem (see Props tables), a subcomponent that’s a light wrapper around <hr> (horizontal break) or <span> elements.

Label

Menu has a label (the label prop), which is separate from any text in the trigger element and appears above the trigger element. The label is required for accessibility reasons, but displaying it is optional. If the design doesn’t show a label above the trigger element, treat the label as hidden. Use the hideLabel prop to hide it, and work with the designer to make sure that label is set with an appropriate value.

Repository

Implementation links

Menu directory in Bitbucket

MenuItem 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 accessability 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 { Menu, MenuItem } 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 Menu from '@athena/forge/Menu';
import MenuItem from '@athena/forge/MenuItem';

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 Menu from '@athena/forge/dist/Menu';
import MenuItem from '@athena/forge/dist/MenuItem';

Props