# Menu

Component of the SBB design system Lyne.

- Package: `@sbb-esta/lyne-elements` (Angular: `@sbb-esta/lyne-angular`)
- Structure: main element with parts; use parts only within the element they belong to
- Categories: Navigation
- Status: Design guidelines complete

## Links

- Page on digital.sbb.ch: https://digital.sbb.ch/en/design-system/lyne/components/menu/
- Storybook: https://lyne-elements.app.sbb.ch/?path=/docs/elements-menu--docs
- Angular (`@sbb-esta/lyne-angular`): https://lyne-angular.app.sbb.ch/angular/components/menu/overview (API: https://lyne-angular.app.sbb.ch/angular/components/menu/api)
- Figma: https://www.figma.com/design/mWknI2rC5DJmOgRO61WKai/Lyne-Components?node-id=7491-39
- GitHub: https://github.com/sbb-design-systems/lyne-components/tree/v5.12.0/src/elements/menu

## Elements

- `sbb-menu`: It displays a contextual menu with one or more action element.
  - `sbb-menu-button` (also as `sbb-menu-link`), only within `sbb-menu`: It displays a button element that can be used in the `sbb-menu` component.

## Overview

### What does the component do?
A menu shows context-dependent actions or links for a specific element. It is opened by another element, e.g. a [button](https://digital.sbb.ch/en/design-system/lyne/components/button/). On small screens it appears as a sheet, on large screens as a floating menu.

### When should the component be used?
* To offer actions or links that belong to a specific element or content.
* To save space for actions that are needed less often.
* As a simple selection, e.g. for the language.

### Rules.
* Menu items have short labels, are logically grouped and sensibly ordered.
* A menu contains only a few items.
* Actions are buttons, references are links.
* Submenus are possible but should be used sparingly.
* If the menu is used as a selection, the active item must also be recognisable for screen readers (`aria-pressed`).
* A [badge](https://digital.sbb.ch/en/design-system/lyne/components/badge/) on an item needs a text alternative for screen readers.

## Implementation (web components)

The `<sbb-menu>` is a component that can be attached to any element to open and display a custom context menu,
which allows to perform actions relevant to the current task by using the `<sbb-menu-button>`
or to navigate within or outside the application by using the `<sbb-menu-link>` component along with it.

```html
<!-- Trigger element -->
<sbb-button id="menu-trigger">Menu trigger</sbb-button>

<!-- Menu component with menu actions -->
<sbb-menu trigger="menu-trigger">
  <sbb-menu-link icon="link-small" href="https://www.sbb.ch/en">View</sbb-menu-link>
  <sbb-menu-button icon="pen-small">Edit</sbb-menu-button>
  <sbb-menu-button icon="swisspass-small" sbb-badge="12" aria-label="Details, containing 12 items">
    Details
  </sbb-menu-button>
  <sbb-divider></sbb-divider>
  <sbb-menu-button icon="cross-small">Cancel</sbb-menu-button>
</sbb-menu>
```

You can provide custom content inside the `<sbb-menu>`:

```html
<sbb-menu>
  <div>Christina Müller</div>
  <span>UIS9057</span>
  <sbb-block-link href="https://www.sbb.ch/en" size="xs">Profile</sbb-block-link>
  <sbb-divider></sbb-divider>
  <sbb-menu-link icon="link-small" href="https://www.sbb.ch/en">View</sbb-menu-link>
  <sbb-menu-button icon="pen-small">Edit</sbb-menu-button>
  <sbb-menu-button icon="swisspass-small" sbb-badge="12" aria-label="Details, containing 12 items">
    Details
  </sbb-menu-button>
  <sbb-divider></sbb-divider>
  <sbb-menu-button icon="cross-small">Cancel</sbb-menu-button>
</sbb-menu>
```

### Interactions

The `<sbb-menu>` appears on trigger left click, and it is displayed as a sheet with a backdrop on mobile,  
while on desktop it will be shown as a floating menu, and it will calculate the optimal position relative to the trigger element
by evaluating the available space with the following priority: start/below, start/above, end/below, end/above.

Clicking in the backdrop or pressing the `ESC` key closes the menu.

The element that will trigger the menu dialog must be set using the `trigger` property.

```html
<!-- Trigger element -->
<sbb-button id="menu-trigger">Menu trigger</sbb-button>

<!-- Menu component with custom content and menu actions -->
<sbb-menu trigger="menu-trigger">...</sbb-menu>
```

### Nesting menus

It is possible to create submenus by connecting a menu to a `<sbb-menu-button>`/`<sbb-menu-link>` element.
On smaller screens, submenus will automatically display a back button to navigate back to the parent menu.

Please note that nesting the menus in DOM is not supported. The `<sbb-menu>` elements have to be siblings in order to work.

```html
<sbb-menu>
  <sbb-menu-button icon="pen-small" id="submenu-trigger">Submenu trigger</sbb-menu-button>
</sbb-menu>
<sbb-menu trigger="submenu-trigger">
  <sbb-menu-link icon="link-small" href="https://www.sbb.ch/en">View</sbb-menu-link>
  <sbb-menu-button icon="swisspass-small" sbb-badge="12">Details</sbb-menu-button>
</sbb-menu>
```

### Menu Actions

There are two types of menu actions: links and buttons, represented by the `<sbb-menu-link>`
and `<sbb-menu-button>` components respectively.

```html
<sbb-menu-link href="#info" target="_blank">Link</sbb-menu-link>
<sbb-menu-button>Button</sbb-menu-button>
```

The components can optionally display an `<sbb-icon>` at the component start using the `iconName` property
or via custom content using the `icon` slot.

```html
<sbb-menu-link href="#" icon-name="pie-small">Another text</sbb-menu-link>
<sbb-menu-button><sbb-icon slot="icon" name="pie-small" />Another text</sbb-menu-button>
```

#### Badge

A badge can be rendered on the icon as white text in a red circle via the `sbb-badge` attribute.
It's recommended to hide the badge when the menu action is disabled.
It's mandatory to provide the badge information for screen readers either with an `aria-label`
(or `accessibility-label` for `<sbb-menu-link>`) or a hidden text.

```html
<sbb-menu-link
  href="#"
  sbb-badge="2"
  accessibility-label="Show messages, 2 new messages available"
  icon-name="pie-small"
>
  Messages
</sbb-menu-link>
<sbb-menu-button
  sbb-badge="2"
  aria-label="Show messages, 2 new messages available"
  icon-name="pie-small"
>
  Messages
</sbb-menu-button>
```

### Accessibility

The `<sbb-menu>` uses the roles `menu` and `menuitem` for children.

As the menu opens, the focus will automatically be set to the first focusable
item within the component (unless manually specified, see below).
When using the `<sbb-menu>` as a select (e.g. language selection) it's recommended to use the `aria-pressed` attribute
to identify which actions are active and which are not.

It is possible to navigate the slotted `<sbb-menu-button>`/`<sbb-menu-link>` via keyboard using arrow keys or page keys
(<kbd>Home</kbd>, <kbd>PageUp</kbd>, <kbd>End</kbd> and <kbd>PageDown</kbd>).
If the trigger element for a nested menu is focused, <kbd>ArrowRight</kbd> will open and focus the submenu;
if the focus is currently on a nested menu, <kbd>ArrowLeft</kbd> will close the current menu and go back to the parent menu.

#### Controlling initial focus

The first element with the attribute `sbb-focus-initial` will receive focus on opening.
If the attribute is not used, the first focusable element receives focus (recommended).

```html
<sbb-menu>
  <sbb-block-link href="https://www.sbb.ch/en" size="xs">Profile</sbb-block-link>
  <sbb-menu-link sbb-focus-initial icon="link-small" href="https://www.sbb.ch/en">
    Receives initial focus
  </sbb-menu-link>
</sbb-menu>
```

#### Interactive disabled buttons

Native disabled elements cannot receive focus and do not dispatch any events. This can
be problematic in some cases because it can prevent the app from telling the user why the button is
disabled. Consumers can use the `disabledInteractive` property to style the button as disabled but allow for
it to receive focus and dispatch events. The button will have `aria-disabled="true"` for assistive
technology. It is the consumers responsibility to provide a reason for the element being disabled.
This can be achieved by adding an `aria-label`, `aria-labelledby` or `aria-describedby` attribute.

**Note:** Using the `disabledInteractive` property can result in buttons that previously prevented
actions to no longer do so, for example a submit button in a form. When using this input, you should
guard against such cases in your component.

```html
<sbb-menu>
  ...
  <sbb-menu-button disabled-interactive> Edit </sbb-menu-button>
  ...
</sbb-menu>
```

## API (web components)

Full API tables (attributes, events, slots, CSS properties): https://digital.sbb.ch/en/design-system/lyne/components/menu/api.md
