menu item

The menu item is the smallest element of the Context Menu.

It can be either a link or a button. It has a mandatory label and optional icon and divider.

A link can be used for first level items.

A button can be used for:

  • groups (with an arrow down icon)
  • showing / hiding second level items (with an arrow right icon)
Ensure that an instance of this component is used inside a parent component with role 'menu', 'menubar' or 'group'.

This component works with all its features only in browsers that have support for the :has CSS selector. Please refer to the reference on MDN.
If you need to run this component in a browser with no support for the :has CSS selector, please use the FROK Release 3.6.x.

Mandatory and optional parts

The menu item dows have multiple parts that can be used, only the label is mandatory. Optional parts are:

  • icon in front of the label
  • secondary label
  • badge
  • arrow right or arrow down to indicate sub menus
  • divider to separate multiple menu items

Indent variant

The indent variant of the component, can occur in two versions: with or without active indicator in form of an ui icon checkmark.

For the rest of the possible parts, the same rules apply as for the non-indent version.


component variations

Default

<li class="a-menu-item" role="none">
  <div class="a-menu-item__wrapper">
    <a
      href="/#"
      role="menuitem"
      class="a-menu-item__link"
      aria-disabled="false"
    >
      <span class="a-menu-item__label">Label</span>
    </a>
  </div>
</li>

With icon

<li class="a-menu-item" role="none">
  <div class="a-menu-item__wrapper">
    <a
      href="/#"
      role="menuitem"
      class="a-menu-item__link"
      aria-disabled="false"
    >
      <i class="a-icon boschicon-bosch-ic-emoji-happy"></i>
      <span class="a-menu-item__label">Label</span>
    </a>
  </div>
</li>

With secondary label

<li class="a-menu-item" role="none">
  <div class="a-menu-item__wrapper">
    <a
      href="/#"
      role="menuitem"
      class="a-menu-item__link"
      aria-disabled="false"
    >
      <span class="a-menu-item__label">Label</span>
      <span class="a-menu-item__label">Secondary Label</span>
    </a>
  </div>
</li>

With badge

<li class="a-menu-item" role="none">
  <div class="a-menu-item__wrapper">
    <a
      href="/#"
      role="menuitem"
      class="a-menu-item__link"
      aria-disabled="false"
    >
      <span class="a-menu-item__label">Label</span>
      <div class="a-badge" role="status" aria-live="off">1</div>
    </a>
  </div>
</li>

With arrow right

  • <li class="a-menu-item" role="none">
      <div class="a-menu-item__wrapper">
        <button
          type="button"
          role="menuitem"
          class="a-menu-item__side-menu"
          aria-disabled="false"
        >
          <span class="a-menu-item__label">Label</span>
          <i class="a-icon ui-ic-nosafe-lr-right-small"></i>
        </button>
      </div>
    </li>

    With arrow down

  • <li class="a-menu-item" role="none">
      <div class="a-menu-item__wrapper">
        <button
          type="button"
          role="menuitem"
          class="a-menu-item__group"
          aria-disabled="false"
          aria-label="open group"
        >
          <span class="a-menu-item__label">Label</span>
          <i class="a-icon ui-ic-down-small"></i>
        </button>
      </div>
    </li>

    With icon and secondary label

    <li class="a-menu-item" role="none">
      <div class="a-menu-item__wrapper">
        <a
          href="/#"
          role="menuitem"
          class="a-menu-item__link"
          aria-disabled="false"
        >
          <i class="a-icon boschicon-bosch-ic-emoji-happy"></i>
          <span class="a-menu-item__label">Label</span>
          <span class="a-menu-item__label">Secondary Label</span>
        </a>
      </div>
    </li>

    With icon, secondary label and badge

    <li class="a-menu-item" role="none">
      <div class="a-menu-item__wrapper">
        <a
          href="/#"
          role="menuitem"
          class="a-menu-item__link"
          aria-disabled="false"
        >
          <i class="a-icon boschicon-bosch-ic-emoji-happy"></i>
          <span class="a-menu-item__label">Label</span>
          <span class="a-menu-item__label">Secondary Label</span>
          <div class="a-badge" role="status" aria-live="off">1</div>
        </a>
      </div>
    </li>

    With icon, secondary label, badge and arrow right

  • <li class="a-menu-item" role="none">
      <div class="a-menu-item__wrapper">
        <button
          type="button"
          role="menuitem"
          class="a-menu-item__side-menu"
          aria-disabled="false"
        >
          <i class="a-icon boschicon-bosch-ic-emoji-happy"></i>
          <span class="a-menu-item__label">Label</span>
          <span class="a-menu-item__label">Secondary Label</span>
          <div class="a-badge" role="status" aria-live="off">1</div>
          <i class="a-icon ui-ic-nosafe-lr-right-small"></i>
        </button>
      </div>
    </li>

    With icon, secondary label, badge and arrow down

  • <li class="a-menu-item" role="none">
      <div class="a-menu-item__wrapper">
        <button
          type="button"
          role="menuitem"
          class="a-menu-item__group"
          aria-disabled="false"
          aria-label="open group"
        >
          <i class="a-icon boschicon-bosch-ic-emoji-happy"></i>
          <span class="a-menu-item__label">Label</span>
          <span class="a-menu-item__label">Secondary Label</span>
          <div class="a-badge" role="status" aria-live="off">1</div>
          <i class="a-icon ui-ic-down-small"></i>
        </button>
      </div>
    </li>

    With icon, secondary label, badge, arrow down and divider


  • <li class="a-menu-item" role="none">
      <div class="a-menu-item__wrapper">
        <button
          type="button"
          role="menuitem"
          class="a-menu-item__group"
          aria-disabled="false"
          aria-label="open group"
        >
          <i class="a-icon boschicon-bosch-ic-emoji-happy"></i>
          <span class="a-menu-item__label">Label</span>
          <span class="a-menu-item__label">Secondary Label</span>
          <div class="a-badge" role="status" aria-live="off">1</div>
          <i class="a-icon ui-ic-down-small"></i>
        </button>
      </div>
    </li>
    <hr class="a-divider" />

    With icon, secondary label, badge and arrow down disabled

  • <li class="a-menu-item -disabled" role="none">
      <div class="a-menu-item__wrapper">
        <button
          type="button"
          role="menuitem"
          class="a-menu-item__group"
          aria-disabled="true"
          tabindex="-1"
          aria-label="open group"
        >
          <i class="a-icon boschicon-bosch-ic-emoji-happy"></i>
          <span class="a-menu-item__label">Label</span>
          <span class="a-menu-item__label">Secondary Label</span>
          <div class="a-badge" role="status" aria-live="off">1</div>
          <i class="a-icon ui-ic-down-small"></i>
        </button>
      </div>
    </li>

    With icon, secondary label, badge, arrow down and divider disabled


  • <li class="a-menu-item -disabled" role="none">
      <div class="a-menu-item__wrapper">
        <button
          type="button"
          role="menuitem"
          class="a-menu-item__group"
          aria-disabled="true"
          tabindex="-1"
          aria-label="open group"
        >
          <i class="a-icon boschicon-bosch-ic-emoji-happy"></i>
          <span class="a-menu-item__label">Label</span>
          <span class="a-menu-item__label">Secondary Label</span>
          <div class="a-badge" role="status" aria-live="off">1</div>
          <i class="a-icon ui-ic-down-small"></i>
        </button>
      </div>
    </li>
    <hr class="a-divider" />

    Active

  • <li class="a-menu-item -selected" role="none">
      <div class="a-menu-item__wrapper">
        <button
          type="button"
          role="menuitem"
          class="a-menu-item__group"
          aria-disabled="false"
          aria-label="open group"
        >
          <i class="a-icon boschicon-bosch-ic-emoji-happy"></i>
          <span class="a-menu-item__label">Label</span>
          <span class="a-menu-item__label">Secondary Label</span>
          <div class="a-badge" role="status" aria-live="off">1</div>
          <i class="a-icon ui-ic-down-small"></i>
        </button>
      </div>
    </li>

    Indent

  • <li class="a-menu-item -indent" role="none">
      <div class="a-menu-item__wrapper">
        <button
          type="button"
          role="menuitem"
          class="a-menu-item__group"
          aria-disabled="false"
          aria-label="open group"
        >
          <i class="a-icon boschicon-bosch-ic-emoji-happy"></i>
          <span class="a-menu-item__label">Label</span>
          <span class="a-menu-item__label">Secondary Label</span>
          <div class="a-badge" role="status" aria-live="off">1</div>
          <i class="a-icon ui-ic-down-small"></i>
        </button>
      </div>
    </li>

    Indent with divider


  • <li class="a-menu-item -indent" role="none">
      <div class="a-menu-item__wrapper">
        <button
          type="button"
          role="menuitem"
          class="a-menu-item__group"
          aria-disabled="false"
          aria-label="open group"
        >
          <i class="a-icon boschicon-bosch-ic-emoji-happy"></i>
          <span class="a-menu-item__label">Label</span>
          <span class="a-menu-item__label">Secondary Label</span>
          <div class="a-badge" role="status" aria-live="off">1</div>
          <i class="a-icon ui-ic-down-small"></i>
        </button>
      </div>
    </li>
    <hr class="a-divider" />

    Indent active

  • <li class="a-menu-item -indent -selected" role="none">
      <div class="a-menu-item__wrapper">
        <button
          type="button"
          role="menuitem"
          class="a-menu-item__group"
          aria-disabled="false"
          aria-label="open group"
        >
          <i class="a-icon boschicon-bosch-ic-emoji-happy"></i>
          <span class="a-menu-item__label">Label</span>
          <span class="a-menu-item__label">Secondary Label</span>
          <div class="a-badge" role="status" aria-live="off">1</div>
          <i class="a-icon ui-ic-down-small"></i>
        </button>
      </div>
    </li>

    Indent disabled

  • <li class="a-menu-item -disabled -indent" role="none">
      <div class="a-menu-item__wrapper">
        <button
          type="button"
          role="menuitem"
          class="a-menu-item__group"
          aria-disabled="true"
          tabindex="-1"
          aria-label="open group"
        >
          <i class="a-icon boschicon-bosch-ic-emoji-happy"></i>
          <span class="a-menu-item__label">Label</span>
          <span class="a-menu-item__label">Secondary Label</span>
          <div class="a-badge" role="status" aria-live="off">1</div>
          <i class="a-icon ui-ic-down-small"></i>
        </button>
      </div>
    </li>

    Indent active disabled

  • <li class="a-menu-item -disabled -indent -selected" role="none">
      <div class="a-menu-item__wrapper">
        <button
          type="button"
          role="menuitem"
          class="a-menu-item__group"
          aria-disabled="true"
          tabindex="-1"
          aria-label="open group"
        >
          <i class="a-icon boschicon-bosch-ic-emoji-happy"></i>
          <span class="a-menu-item__label">Label</span>
          <span class="a-menu-item__label">Secondary Label</span>
          <div class="a-badge" role="status" aria-live="off">1</div>
          <i class="a-icon ui-ic-down-small"></i>
        </button>
      </div>
    </li>

    indent and selected

  • <li class="a-menu-item -indent" role="none">
      <div class="a-menu-item__wrapper">
        <i class="a-icon a-menu-item__state ui-ic-checkmark"></i>
        <button
          type="button"
          role="menuitem"
          class="a-menu-item__group"
          aria-disabled="false"
          aria-label="open group"
        >
          <i class="a-icon boschicon-bosch-ic-emoji-happy"></i>
          <span class="a-menu-item__label">Label</span>
          <span class="a-menu-item__label">Secondary Label</span>
          <div class="a-badge" role="status" aria-live="off">1</div>
          <i class="a-icon ui-ic-down-small"></i>
        </button>
      </div>
    </li>

    indent, active and selected

  • <li class="a-menu-item -indent -selected" role="none">
      <div class="a-menu-item__wrapper">
        <i class="a-icon a-menu-item__state ui-ic-checkmark"></i>
        <button
          type="button"
          role="menuitem"
          class="a-menu-item__group"
          aria-disabled="false"
          aria-label="open group"
        >
          <i class="a-icon boschicon-bosch-ic-emoji-happy"></i>
          <span class="a-menu-item__label">Label</span>
          <span class="a-menu-item__label">Secondary Label</span>
          <div class="a-badge" role="status" aria-live="off">1</div>
          <i class="a-icon ui-ic-down-small"></i>
        </button>
      </div>
    </li>

    additional content

    styles SCSS

    .a-menu-item {
      margin: 0;
      padding: 0;
      width: 100%;
    
      /* stylelint-disable a11y/content-property-no-static-value */
      &::before {
        content: unset;
      }
      /* stylelint-enable a11y/content-property-no-static-value */
    
    
      &__wrapper {
        position: relative;
        display: grid;
        grid-template-columns: 1fr;
        grid-template-areas: 'label';
        align-items: center;
        height: auto;
        justify-content: center;
        background-color: var(--plain__enabled__fill__default);
        color: var(--plain__enabled__front__default);
    
        // interactive states
        &:hover {
          background-color: var(--plain__enabled__fill__hovered);
          color: var(--plain__enabled__front__hovered);
          text-decoration: none;
          cursor: pointer;
        }
        
        &:active {
          background-color: var(--plain__enabled__fill__pressed);
          color: var(--plain__enabled__front__pressed);
        }
    
        &:has( > *:focus-visible) {
          // @include focus-inside;
          // margin: 1rem;
    
          // Outline for keyboard navigation
          &::before,
          &::after {
            position: absolute;
            content: '';
            width: 100%;
            height: 100%;
            top: 0;
            left: 0;
            z-index: 1;
          }
    
          &::before {
            outline: 3px solid var(--plain__enabled__front__default);
            outline-offset: -3px;
          }
          &::after {
            outline: 3px solid var(--background);
            outline-offset: -6px;
          }
        }
      }
    
      &.-disabled > .a-menu-item__wrapper {
        background-color: var(--plain__disabled__fill__default);
        color: var(--plain__disabled__front__default);
        cursor: not-allowed;
    
        .a-badge {
          background-color: var(--major-accent__disabled__fill__default);
          color: var(--major-accent__disabled__front__default);
        }
      }
    
      // indent variant layout adjustments
      &.-indent .a-menu-item__wrapper {
        grid-template-columns: 2.875rem 1fr;
        grid-template-areas: 'state label';
    
        & .a-menu-item__link,
        & .a-menu-item__button,
        & .a-menu-item__group,
        & .a-menu-item__side-menu {
          padding-inline-start: 0;
        }
    
        &:has([class^="a-menu-item"] > .a-icon) {
          grid-template-columns: 2.75rem 1fr;
        }
      }
    
      // styles for each part of the menuItem
      &__state {
        display: grid;
        place-content: center;
        grid-area: state;
        height: 3rem;
        background-color: inherit;
        color: inherit;
      }
    
      a,
      a:visited {
        text-decoration: none;
        color: inherit;
        background-color: inherit;
      }
    
      &__link,
      &__button,
      &__group,
      &__side-menu {
        grid-area: label;
        text-align: left;
        display: grid;
        grid-auto-flow: column;
        grid-auto-columns: auto;
        align-items: center;
        column-gap: 0.5rem;
        width: 100%;
        padding: 0.75rem 1rem;
        border: 0;
        background-color: inherit;
        color: inherit;
    
        // different grid layouts for each possible content
        &:has(> .a-menu-item__label) {
          grid-template-columns: 1fr;
        }
    
        &:has(> .a-menu-item__label + .a-menu-item__label) {
          grid-template-columns: 2fr 1fr;
        }
    
        &:has(> .a-icon:first-child + .a-menu-item__label) {
          grid-template-columns: auto 1fr;
        }
    
        &:has(> .a-icon:first-child + .a-menu-item__label + .a-menu-item__label) {
          grid-template-columns: auto 2fr 1fr;
        }
    
        &:has(>.a-icon:first-child) {
          padding-inline-start: 0.75rem;
        }
    
        // reset focus states of button and link
        &:focus-visible {
          outline: none;
          
          &::after {
            content: none;
          }
        }
    
        .a-icon {
          margin: unset;
        }
      }
    
      &__label {
        color: inherit;
        white-space: nowrap;
        text-overflow: ellipsis;
        overflow: hidden;
      }
    
      &__label:nth-of-type(2) {
        text-decoration: none;
        text-align: end;
    
        @include size-s;
      }
    
      + .a-divider {
        margin-top: 0;
        margin-bottom: 0;
        margin-inline: 1rem;
      }
    }
    
    // add styles for selected state here, to have them in one place
    .a-menu-item.-selected {
      @extend .-contrast;
    }
    
    // this is needed to switch to the primary-look-a-like selected state
    .-contrast .a-menu-item.-selected {
      @extend .-primary;
    }```