Soracom

Design System
  1. Home
  2. Design system
  3. Elements
  4. Menubutton

Menubutton

Menubutton is for dynamically displaying navigation menus

This component requires some Javascript for certain functionality, and implementing W3C WAI-ARIA accessibility recommendations

Options

Basic usage

ds-menubutton can use either an html details and summary element; or div and button.

ds-menu content uses the available options of ds-menu. See ds-menu for additional documentation on menu items.

Using details/summary elements

When using a details element, the summary element when clicked will toggle the contents of ds-menu - the menu container, without the need for any javascript.

Basic usage - details element with menubutton styled as text (click example to view)

html
Copy
<details class="ds-menubutton">
  <summary class="ds-text">Text content</summary>
  <div class="ds-menu">
    <ul>
      <li>
        <a href="#">Change email</a>
      </li>
      <li>
        <a href="#">Contact information</a>
      </li>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
  </div>
</details>

Basic usage - details element with menubutton styled as a button (click example to view)

html
Copy
<details class="ds-menubutton">
  <summary>
    <span class="ds-button --primary --icon-settings">
      <span>Button label</span>
    </span>
  </summary>
  <div class="ds-menu">
    <ul>
      <li>
        <a href="#">Change email</a>
      </li>
      <li>
        <a href="#">Contact information</a>
      </li>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
  </div>
</details>

Basic usage - details element with menubutton styled as label and a small icon (click example to view)

html
Copy
<details class="ds-menubutton">
  <summary>
    <span class="ds-button --label --icon-settings"
      ><span>Text content</span></span
    >
  </summary>
  <div class="ds-menu">
    <ul>
      <li>
        <a href="#">Change email</a>
      </li>
      <li>
        <a href="#">Contact information</a>
      </li>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
  </div>
</details>

Using div and button elements

When using a div element, the button element requires additional javascript to open and close the menu.

At minimum, the javascript should:

  • Set the button attribute aria-expanded="true" to show the menu contents.
  • Add the class --open to menubutton container – <div class="ds-menubutton --open"> to correctly set the menubuttons z-index.

Basic usage - div element with a button as the menubutton (click example to view)

html
Copy
<div class="ds-menubutton">
  <button class="ds-button --primary --icon-settings">
    <span>Button label</span>
  </button>
  <div class="ds-menu">
    <ul>
      <li>
        <a href="#">Change email</a>
      </li>
      <li>
        <a href="#">Contact information</a>
      </li>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
  </div>
</div>

Position

By default the menubutton menu is displayed below and aligned to the left of the button element.

As an alternative, the following positions are supported:

  • --right
  • --fixed-left
  • --fixed-top-left
  • --fixed-right
  • --fixed-top-right

Menubuttons used inside a ds-header__controls element will automatically display aligned right.

Menu position - right (click example to view)

html
Copy
<details class="ds-menubutton --right">
  <summary>
    <span class="ds-button --primary --icon-settings">
      <span>Button label</span>
    </span>
  </summary>
  <div class="ds-menu">
    <div class="ds-text --label">Account</div>
    <ul>
      <li>
        <a href="#" class="ds-text --icon-settings"
          >Account settings<span>Manage account settings and features</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-signin"
          >Change email<span>Update your login email</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-user">Contact information</a>
      </li>
    </ul>
    <div class="ds-text --label">Payment</div>
    <ul>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Logout</a>
      </li>
    </ul>
  </div>
</details>

Menu position - fixed left (click example to view)

html
Copy
<details class="ds-menubutton --fixed-left">
  <summary>
    <span class="ds-button --primary --icon-settings">
      <span>Button label</span>
    </span>
  </summary>
  <div class="ds-menu">
    <div class="ds-text --label">Account</div>
    <ul>
      <li>
        <a href="#" class="ds-text --icon-settings"
          >Account settings<span>Manage account settings and features</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-signin"
          >Change email<span>Update your login email</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-user">Contact information</a>
      </li>
    </ul>
    <div class="ds-text --label">Payment</div>
    <ul>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Logout</a>
      </li>
    </ul>
  </div>
</details>

Menu position - fixed top-left (click example to view)

html
Copy
<details class="ds-menubutton --fixed-top-left">
  <summary>
    <span class="ds-button --primary --icon-settings">
      <span>Button label</span>
    </span>
  </summary>
  <div class="ds-menu">
    <div class="ds-text --label">Account</div>
    <ul>
      <li>
        <a href="#" class="ds-text --icon-settings"
          >Account settings<span>Manage account settings and features</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-signin"
          >Change email<span>Update your login email</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-user">Contact information</a>
      </li>
    </ul>
    <div class="ds-text --label">Payment</div>
    <ul>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Logout</a>
      </li>
    </ul>
  </div>
</details>

Menu position - fixed right (click example to view)

html
Copy
<details class="ds-menubutton --fixed-right">
  <summary>
    <span class="ds-button --primary --icon-settings">
      <span>Button label</span>
    </span>
  </summary>
  <div class="ds-menu">
    <div class="ds-text --label">Account</div>
    <ul>
      <li>
        <a href="#" class="ds-text --icon-settings"
          >Account settings<span>Manage account settings and features</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-signin"
          >Change email<span>Update your login email</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-user">Contact information</a>
      </li>
    </ul>
    <div class="ds-text --label">Payment</div>
    <ul>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Logout</a>
      </li>
    </ul>
  </div>
</details>

Menu position - fixed top right (click example to view)

html
Copy
<details class="ds-menubutton --fixed-top-right">
  <summary>
    <span class="ds-button --primary --icon-settings">
      <span>Button label</span>
    </span>
  </summary>
  <div class="ds-menu">
    <div class="ds-text --label">Account</div>
    <ul>
      <li>
        <a href="#" class="ds-text --icon-settings"
          >Account settings<span>Manage account settings and features</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-signin"
          >Change email<span>Update your login email</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-user">Contact information</a>
      </li>
    </ul>
    <div class="ds-text --label">Payment</div>
    <ul>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Logout</a>
      </li>
    </ul>
  </div>
</details>

Menu position - fixed right (click example to view)

html
Copy
<details class="ds-menubutton --constrain-vh --fixed-top-right">
  <summary>
    <span class="ds-button --primary --icon-settings">
      <span>Button label</span>
    </span>
  </summary>
  <div class="ds-menu">
    <div class="ds-text --label">Account</div>
    <ul>
      <li>
        <a href="#" class="ds-text --icon-settings"
          >Account settings<span>Manage account settings and features</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-signin"
          >Change email<span>Update your login email</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-user">Contact information</a>
      </li>
    </ul>
    <div class="ds-text --label">Payment</div>
    <ul>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Logout</a>
      </li>
    </ul>
    <div class="ds-text --label">Account</div>
    <ul>
      <li>
        <a href="#" class="ds-text --icon-settings"
          >Account settings<span>Manage account settings and features</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-signin"
          >Change email<span>Update your login email</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-user">Contact information</a>
      </li>
    </ul>
    <div class="ds-text --label">Payment</div>
    <ul>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Logout</a>
      </li>
    </ul>
  </div>
</details>

Width

Narrow, mid, wide, full

--full width sets the menu to be the same width of the menubutton

Menu ds-menu at default, narrow, mid, wide and full sizes (click buttons to view)

html
Copy
<!-- 1. Default -->
<details class="ds-menubutton">
  <summary>
    <span class="ds-button --primary --icon-settings">
      <span>Button label</span>
    </span>
  </summary>
  <div class="ds-menu">
    <ul>
      <li>
        <a href="#">Change email</a>
      </li>
      <li>
        <a href="#" class="ds-text --icon-settings"
          >Account settings<span>Manage account settings and features</span></a
        >
      </li>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
  </div>
</details>
<!-- 2. ds-menu --narrow -->
<details class="ds-menubutton">
  <summary>
    <span class="ds-button --primary --icon-settings">
      <span>Button label</span>
    </span>
  </summary>
  <div class="ds-menu --narrow">
    <ul>
      <li>
        <a href="#">Change email</a>
      </li>
      <li>
        <a href="#"
          >Account settings<span>Manage account settings and features</span></a
        >
      </li>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
  </div>
</details>
<!-- 3. ds-menu --mid -->
<details class="ds-menubutton">
  <summary>
    <span class="ds-button --primary --icon-settings">
      <span>Button label</span>
    </span>
  </summary>
  <div class="ds-menu --mid">
    <ul>
      <li>
        <a href="#">Change email</a>
      </li>
      <li>
        <a href="#" class="ds-text --icon-settings"
          >Account settings<span>Manage account settings and features</span></a
        >
      </li>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
  </div>
</details>
<!-- 4. ds-menu --wide -->
<details class="ds-menubutton">
  <summary>
    <span class="ds-button --primary --icon-settings">
      <span>Button label</span>
    </span>
  </summary>
  <div class="ds-menu --wide">
    <ul>
      <li>
        <a href="#">Change email</a>
      </li>
      <li>
        <a href="#" class="ds-text --icon-settings"
          >Account settings<span>Manage account settings and features</span></a
        >
      </li>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
  </div>
</details>
<!-- 5. ds-menu --full -->
<details class="ds-menubutton">
  <summary>
    <span class="ds-button --primary --icon-settings">
      <span>Button label which is quite wide</span>
    </span>
  </summary>
  <div class="ds-menu --full">
    <ul>
      <li>
        <a href="#">Change email</a>
      </li>
      <li>
        <a href="#" class="ds-text --icon-settings"
          >Account settings<span>Manage account settings and features</span></a
        >
      </li>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
  </div>
</details>

Height

By default the menu will be the height of the menu contents. You can also restrict the overall height of the menu and cause the contents to scroll. If the menu can scroll, a shadow will be added at the bottom/top of the menu to indicate the menu is scrollable.

You can apply these settings to either a ds-menubutton or to a standalone ds-menu component.

There are two ways to restrict the height.

Restrict the height to the viewport

Adding the class --viewport to the menu will restrict the height to 100vh - --ds-header-height (usually 100vh - 60px) and force the menu to scroll.

Using viewport height - if the browser height is less than the menu height, the menu will scroll

html
Copy
<details class="ds-menubutton">
  <summary>
    <span class="ds-button --primary --icon-settings">
      <span>Button label</span>
    </span>
  </summary>
  <div class="ds-menu --viewport">
    <ul>
      <li>
        <a href="#">Details</a>
      </li>
      <li>
        <a href="#">Activate</a>
      </li>
      <li>
        <a href="#">Deactivate</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Add subscription...</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Delete session</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Change group</a>
      </li>
      <li>
        <a href="#">Change speed class</a>
      </li>
      <li>
        <a href="#">Change expiry</a>
      </li>
      <li>
        <a href="#">Enable IMEI lock</a>
      </li>
      <li>
        <a href="#">Unset IMEI lock</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Check logs</a>
      </li>
      <li>
        <a href="#">Harvest data</a>
      </li>
      <li>
        <a href="#">Send SMS</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">On-demand Remote Access</a>
      </li>
      <li>
        <a href="#">Packet capture</a>
      </li>
      <li>
        <a href="#">Send ping message</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Run diagnostics</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Change termination protection</a>
      </li>
      <li>
        <a href="#">Set to Standby</a>
      </li>
      <li>
        <a href="#">Suspend</a>
      </li>
      <li>
        <a href="#">Terminate</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Transfer to another operator</a>
      </li>
      <li>
        <a href="#">Cancel transfer</a>
      </li>
    </ul>
  </div>
</details>

Restrict the height to a specific size

You can restrict the height by changing the --ds-menu-height value (either in a css file, inline style tag or via javascript).

let myCustomMenu = document.getElementById("customMenu");
myCustomMenu.style.setProperty("--ds-menu-height", "400px");

Setting a height using inline style tag

html
Copy
<details class="ds-menubutton">
  <summary>
    <span class="ds-button --primary --icon-settings">
      <span>Button label</span>
    </span>
  </summary>
  <div class="ds-menu" style="--ds-menu-height: 400px;">
    <ul>
      <li>
        <a href="#">Details</a>
      </li>
      <li>
        <a href="#">Activate</a>
      </li>
      <li>
        <a href="#">Deactivate</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Add subscription...</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Delete session</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Change group</a>
      </li>
      <li>
        <a href="#">Change speed class</a>
      </li>
      <li>
        <a href="#">Change expiry</a>
      </li>
      <li>
        <a href="#">Enable IMEI lock</a>
      </li>
      <li>
        <a href="#">Unset IMEI lock</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Check logs</a>
      </li>
      <li>
        <a href="#">Harvest data</a>
      </li>
      <li>
        <a href="#">Send SMS</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">On-demand Remote Access</a>
      </li>
      <li>
        <a href="#">Packet capture</a>
      </li>
      <li>
        <a href="#">Send ping message</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Run diagnostics</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Change termination protection</a>
      </li>
      <li>
        <a href="#">Set to Standby</a>
      </li>
      <li>
        <a href="#">Suspend</a>
      </li>
      <li>
        <a href="#">Terminate</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Transfer to another operator</a>
      </li>
      <li>
        <a href="#">Cancel transfer</a>
      </li>
    </ul>
  </div>
</details>

Component colors

Adding a color the to the top-level ds-menubutton element will color the button and the drop down menu.

If you need to only color the button (and not the drop down menu), add the color to the ds-button element.

Color the button and menu

Full color example (click example to view)

html
Copy
<details class="ds-menubutton --color-magenta">
  <summary>
    <span class="ds-button --primary --icon-settings">
      <span>Button label</span>
    </span>
  </summary>
  <div class="ds-menu">
    <div class="ds-text --label">Account</div>
    <ul>
      <li>
        <a href="#" class="ds-text --icon-settings"
          >Account settings<span>Manage account settings and features</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-signin"
          >Change email<span>Update your login email</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-user">Contact information</a>
      </li>
    </ul>
    <div class="ds-text --label">Payment</div>
    <ul>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Logout</a>
      </li>
    </ul>
  </div>
</details>

Color the button only

Color button example (click example to view)

html
Copy
<details class="ds-menubutton">
  <summary>
    <span class="ds-button --primary --icon-settings --color-magenta">
      <span>Button label</span>
    </span>
  </summary>
  <div class="ds-menu">
    <div class="ds-text --label">Account</div>
    <ul>
      <li>
        <a href="#" class="ds-text --icon-settings"
          >Account settings<span>Manage account settings and features</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-signin"
          >Change email<span>Update your login email</span></a
        >
      </li>
      <li>
        <a href="#" class="ds-text --icon-user">Contact information</a>
      </li>
    </ul>
    <div class="ds-text --label">Payment</div>
    <ul>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
    <ul>
      <li>
        <a href="#">Logout</a>
      </li>
    </ul>
  </div>
</details>

No dismiss

To prevent clicking outside the menu closing the menu, use the class --no-dismiss.

No dismiss (click example to view)

html
Copy
<details class="ds-menubutton --no-dismiss">
  <summary class="ds-text">Text content</summary>
  <div class="ds-menu">
    <ul>
      <li>
        <a href="#">Change email</a>
      </li>
      <li>
        <a href="#">Contact information</a>
      </li>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
  </div>
</details>

No background

To not show the background modal tint, use the class --no-background.

No dismiss (click example to view)

html
Copy
<details class="ds-menubutton --no-background">
  <summary class="ds-text">Text content</summary>
  <div class="ds-menu">
    <ul>
      <li>
        <a href="#">Change email</a>
      </li>
      <li>
        <a href="#">Contact information</a>
      </li>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
  </div>
</details>

Inline

To show the open menu inline (instead of a popup menu), use the class --inline.

html
Copy
<div class="ds-menubutton --inline">
  <button class="ds-button --primary --icon-settings">
    <span>Button label</span>
  </button>
  <div class="ds-menu">
    <ul>
      <li>
        <a href="#">Change email</a>
      </li>
      <li>
        <a href="#">Contact information</a>
      </li>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
  </div>
</div>

Basic usage - details element with menubutton styled as a button (click example to view)

html
Copy
<details class="ds-menubutton --inline">
  <summary>
    <span class="ds-button --primary --icon-settings">
      <span>Button label</span>
    </span>
  </summary>
  <div class="ds-menu">
    <ul>
      <li>
        <a href="#">Change email</a>
      </li>
      <li>
        <a href="#">Contact information</a>
      </li>
      <li>
        <a href="#">Billing</a>
      </li>
      <li>
        <a href="#">Payment settings</a>
      </li>
    </ul>
  </div>
</details>

Additional menu options

See ds-menu for additional options for menu items.

When ds-menubutton is used inside ds-select, ds-input, or ds-range it will be displayed next to the element and will not wrap when the window is scaled.

html
Copy
<!-- Inside ds-input -->
<div class="ds-input">
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
  <input type="text" />
</div>
<div class="ds-input">
  <input type="text" />
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
</div>
<!-- Inside ds-input ds-button primary -->
<div class="ds-input">
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button --primary">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
  <input type="text" />
</div>
<div class="ds-input">
  <input type="text" />
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button --primary">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
</div>
<!-- Inside ds-input ds-button plain -->
<div class="ds-input">
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button --plain">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
  <input type="text" />
</div>
<div class="ds-input">
  <input type="text" />
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button --plain">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
</div>
<!-- Inside ds-select -->
<div class="ds-select">
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
  <select>
    <option value="AU">Australia</option>
    <option value="JP">Japan</option>
    <option value="US">United States of America</option>
  </select>
</div>
<div class="ds-select">
  <select>
    <option value="AU">Australia</option>
    <option value="JP">Japan</option>
    <option value="US">United States of America</option>
  </select>
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
</div>
<!-- Inside ds-select ds-button primary-->
<div class="ds-select">
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button --primary">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
  <select>
    <option value="AU">Australia</option>
    <option value="JP">Japan</option>
    <option value="US">United States of America</option>
  </select>
</div>
<div class="ds-select">
  <select>
    <option value="AU">Australia</option>
    <option value="JP">Japan</option>
    <option value="US">United States of America</option>
  </select>
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button --primary">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
</div>
<!-- Inside ds-select ds-button plain-->
<div class="ds-select">
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button --plain">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
  <select>
    <option value="AU">Australia</option>
    <option value="JP">Japan</option>
    <option value="US">United States of America</option>
  </select>
</div>
<div class="ds-select">
  <select>
    <option value="AU">Australia</option>
    <option value="JP">Japan</option>
    <option value="US">United States of America</option>
  </select>
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button --plain">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
</div>
<!-- Inside ds-range -->
<div class="ds-range">
  <input type="range" />
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
</div>
<div class="ds-range">
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
  <input type="range" />
</div>
<!-- Inside ds-range ds-button primary-->
<div class="ds-range">
  <input type="range" />
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button --primary">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
</div>
<div class="ds-range">
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button --primary">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
  <input type="range" />
</div>
<!-- Inside ds-range ds-button plain-->
<div class="ds-range">
  <input type="range" />
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button --plain">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
</div>
<div class="ds-range">
  <details class="ds-menubutton">
    <summary>
      <span class="ds-button --plain">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
  <input type="range" />
</div>

Addon menubutton

The --addon styles slightly modify the menubutton to ‘join’ the containing component.

Addon style

html
Copy
<!-- Inside ds-input -->
<div class="ds-input">
  <details class="ds-menubutton --addon">
    <summary>
      <span class="ds-button">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
  <input type="text" />
</div>
<div class="ds-input">
  <input type="text" />
  <details class="ds-menubutton --addon">
    <summary>
      <span class="ds-button">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
</div>
<!-- Inside ds-input ds-button primary-->
<div class="ds-input">
  <details class="ds-menubutton --addon">
    <summary>
      <span class="ds-button --primary">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
  <input type="text" />
</div>
<div class="ds-input">
  <input type="text" />
  <details class="ds-menubutton --addon">
    <summary>
      <span class="ds-button --primary">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
</div>
<!-- Inside ds-input ds-button plain-->
<div class="ds-input">
  <details class="ds-menubutton --addon">
    <summary>
      <span class="ds-button --plain">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
  <input type="text" />
</div>
<div class="ds-input">
  <input type="text" />
  <details class="ds-menubutton --addon">
    <summary>
      <span class="ds-button --plain">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
</div>
<!-- Inside ds-select -->
<div class="ds-select">
  <details class="ds-menubutton --addon">
    <summary>
      <span class="ds-button">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
  <select>
    <option value="AU">Australia</option>
    <option value="JP">Japan</option>
    <option value="US">United States of America</option>
  </select>
</div>
<div class="ds-select">
  <select>
    <option value="AU">Australia</option>
    <option value="JP">Japan</option>
    <option value="US">United States of America</option>
  </select>
  <details class="ds-menubutton --addon">
    <summary>
      <span class="ds-button">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
</div>
<!-- Inside ds-select ds-button primary -->
<div class="ds-select">
  <details class="ds-menubutton --addon">
    <summary>
      <span class="ds-button --primary">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
  <select>
    <option value="AU">Australia</option>
    <option value="JP">Japan</option>
    <option value="US">United States of America</option>
  </select>
</div>
<div class="ds-select">
  <select>
    <option value="AU">Australia</option>
    <option value="JP">Japan</option>
    <option value="US">United States of America</option>
  </select>
  <details class="ds-menubutton --addon">
    <summary>
      <span class="ds-button --primary">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
</div>
<!-- Inside ds-select ds-button plain -->
<div class="ds-select">
  <details class="ds-menubutton --addon">
    <summary>
      <span class="ds-button --plain">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
  <select>
    <option value="AU">Australia</option>
    <option value="JP">Japan</option>
    <option value="US">United States of America</option>
  </select>
</div>
<div class="ds-select">
  <select>
    <option value="AU">Australia</option>
    <option value="JP">Japan</option>
    <option value="US">United States of America</option>
  </select>
  <details class="ds-menubutton --addon">
    <summary>
      <span class="ds-button --plain">
        <span>Button label</span>
      </span>
    </summary>
    <div class="ds-menu">
      <ul>
        <li>
          <a href="#">Change email</a>
        </li>
        <li>
          <a href="#">Contact information</a>
        </li>
      </ul>
    </div>
  </details>
</div>

Javascript

The following example code improves functionality by only allowing one menubutton menu to be open at once.

if (NodeList.prototype.forEach) {
  const menuButtons = document.querySelectorAll(
    '[class*="ds-menubutton"] > summary, [class*="ds-menubutton"] > button'
  );

  menuButtons.forEach((button) => {
    button.addEventListener("click", () => {
      // Keep ARIA attribute in sync with the menu state when toggling
      // the menu open or closed. When using div/button, the aria-expanded
      // attribute controls visibility of the menu.
      let menuState =
        button.parentElement.open ||
        button.getAttribute("aria-expanded") == "true";
      button.setAttribute("aria-expanded", !menuState);
      button.parentElement.classList.toggle("--open");

      // Only allow one menubutton to be open at once
      // When clicked, close all other menubutton instances
      menuButtons.forEach((otherButton) => {
        if (otherButton !== button) {
          otherButton.parentElement.open = false;
          otherButton.setAttribute("aria-expanded", false);
          otherButton.parentElement.classList.remove("--open");
        }
      });
    });
  });
}

Accessibility

Implementation

There are two primary usage cases for ds-menubutton

  • Navigation menu buttons
  • Action menu buttons

Navigation menu buttons primarily contain lists of links that will change the url and essentially display a different page or context. When used in this scenario - no specific W3C-ARIA attributes or custom keyboard functionality should be implemented.

This component is accessible by default when used for navigation menus.

Action menubutton

Action menu buttons are a menu that performs a task on the page, such as opening a modal, changing the status of a feature etc.

This component is not fully accessible by default when used for action menus, it requires the addition of the full aria attributes, and aria specific interactions via javascript.

Role and ARIA attributes

Recommendations for implementing ds-menubutton to meet W3C WAI-ARIA guidelines are as follows:

Menu button (summary|button element)

html
Copy
<summary aria-haspopup="true" aria-expanded="[true|false]">
  Text content
</summary>

<button aria-haspopup="true" aria-expanded="[true|false]">Text content</button>
ElementAttributeRequiredTypeDescription
<summary> or <button>aria-haspopup=“true”RequiredStaticIndicates the button opens a menu
aria-expanded=“true”RequiredDynamic1. Set to true when the menu is open
2. Removed or set to false when the menu is closed

Menu items

html
Copy
<div role="menu" class="ds-menu">
  <ul role="none">
    <li role="none">
      <a role="menuitem" tabindex="-1" href="#">Change email</a>
    </li>
    <li role="none">
      <a role="menuitem" tabindex="-1" href="#">Contact information</a>
    </li>
    <li role="none"><a role="menuitem" tabindex="-1" href="#">Billing</a></li>
    <li role="none">
      <a role="menuitem" tabindex="-1" href="#">Payment settings</a>
    </li>
  </ul>
</div>
ElementAttributeRequiredTypeDescription
<div>role=“menu”RequiredStaticIndicates the element is a menu
<ul>role=“none”RequiredStaticHides implied semantics from assistive technologies
<li>role=“none”RequiredStaticHides implied semantics from assistive technologies
<a>role=“menuitem”RequiredStaticIndicates the element is a menuitem
tabindex=“-1”RequiredStaticPrevents list items being selected using the tab keyboard command

Keyboard access

By default this component can be selected using the browsers native tab keyboard command; space or enter to open or close the menu when the menu button is selected; and tab, shift-tab to move through the menu items.

When used as an action menubutton - to improve accessibility for assistive technology, additional Role, ARIA attributes and javascript is required. The following keyboard controls must be implemented to provide accessible keyboard access.

Menu button - the closed menu button is selected:

KeyRequiredSupportDescription
EnterRequiredNative1. Opens the menu
2. Places focus on the first menu item
SpaceRequiredNative1. Opens the menu
2. Places focus on the first menu item
TabRequiredNativeMove to the next element in the page tab sequence
Down ArrowOptionalJavascript1. Opens the menu
2. Moves focus to the first menu item
Up ArrowOptionalJavascript1. Opens the menu
2. Moves focus to the last menu item

Menu items - the menubutton menu is open:

KeyRequiredSupportDescription
EnterRequiredNativeActivates the selected menu item
EscapeRequiredJavascript1. Closes the menu
2. Moves focus back to the menu button
TabRequiredJavascript1. Closes the menu
2. Move to the next element in the page tab sequence
Down ArrowOptionalJavascriptMoves focus to the next menu item
Up ArrowOptionalJavascriptMoves focus to the previous menu item

Examples

Header example

html
Copy
<header class="ds-header">
  <aside class="ds-header__controls">
    <details class="ds-menubutton">
      <summary>
        <span class="ds-button --primary">
          <span>First menu</span>
        </span>
      </summary>
      <div class="ds-menu">
        <ul>
          <li>
            <a href="#">Language settings</a>
          </li>
          <li>
            <a href="#">Region Setting</a>
          </li>
        </ul>
      </div>
    </details>
    <details class="ds-menubutton">
      <summary>
        <span class="ds-button --primary --icon-settings">
          <span>Second menu</span>
        </span>
      </summary>
      <div class="ds-menu">
        <ul>
          <li>
            <a href="#">Change email</a>
          </li>
          <li>
            <a href="#">Contact information</a>
          </li>
          <li>
            <a href="#">Billing</a>
          </li>
          <li>
            <a href="#">Payment settings</a>
          </li>
        </ul>
      </div>
    </details>
  </aside>
</header>
html
Copy
<details class="ds-menubutton">
  <summary>
    <span class="ds-button --icon-settings">
      <span>Actions</span>
    </span>
  </summary>
  <div class="ds-menu">
    <ul>
      <li>
        <button class="ds-text --icon-clipboard-copy-to">
          Copy algorithm URL
        </button>
      </li>
      <li>
        <button class="ds-text --icon-delete --alert">Delete model</button>
      </li>
    </ul>
  </div>
</details>
Actions

ds-menubutton inside ds-datatable

html
Copy
<table class="ds-datatable">
  <thead>
    <tr>
      <th>Heading one</th>
      <th>Heading two</th>
      <th>Heading three</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Content</td>
      <td>
        <details class="ds-menubutton">
          <summary>
            <span class="ds-button --primary --icon-settings">
              <span>Button label</span>
            </span>
          </summary>
          <div class="ds-menu">
            <ul>
              <li>
                <a href="#">Change email</a>
              </li>
              <li>
                <a href="#">Billing</a>
              </li>
              <li>
                <a href="#">Payment settings</a>
              </li>
            </ul>
          </div>
        </details>
      </td>
      <td>Content</td>
    </tr>
    <tr>
      <td>Content</td>
      <td>
        <details class="ds-menubutton">
          <summary>
            <span class="ds-button --primary --icon-settings">
              <span>Button label</span>
            </span>
          </summary>
          <div class="ds-menu">
            <ul>
              <li>
                <a href="#">Change email</a>
              </li>
              <li>
                <a href="#">Contact information</a>
              </li>
              <li>
                <a href="#">Payment settings</a>
              </li>
            </ul>
          </div>
        </details>
      </td>
      <td>Content</td>
    </tr>
  </tbody>
</table>
Heading one Heading two Heading three
Content
Button label
Content
Content
Button label
Content

ui-menu example

html
Copy
<ui-menu>
  <details class="ds-menubutton ui-menu__root" role="menu">
    <summary>
      <span class="ds-button">
        <span>Actions</span>
        <i class="ds-icon --icon-ui-arrow-down"></i>
      </span>
    </summary>
    <div class="ds-menu ui-menuds-menu" style="min-width: 8em;">
      <details>
        <summary class="ds-text --label">SORACOM Air for cellular</summary>
        <ul>
          <li>
            <a class="--icon-sim" href="#">SIM Management</a>
          </li>
          <li>
            <a class="--icon-email" href="#">Groups</a>
          </li>
          <li>
            <a class="--icon-visible" href="#">Event handler</a>
          </li>
          <li>
            <a class="--icon-light" href="#">VPG</a>
          </li>
        </ul>
      </details>
      <div class="ui-menu__section">
        <ul class="ui-menu__list" role="none">
          <li class="ui-menu__item ui-menu__item-index__0-0">
            <button
              type="button"
              class="ui-menu__item ui-menu__item-index__0-0"
            >
              <ui-span
                ><span>
                  <ui-text-content
                    ><span class="">Update permissions</span></ui-text-content
                  >
                </span></ui-span
              >
            </button>
          </li>
          <li class="ui-menu__item ui-menu__item-index__0-1">
            <button
              type="button"
              class="ui-menu__item ui-menu__item-index__0-1"
            >
              <ui-span
                ><span>
                  <ui-text-content
                    ><span class="">Update email address</span></ui-text-content
                  >
                </span></ui-span
              >
            </button>
          </li>
          <li class="ui-menu__item ui-menu__item-index__0-2">
            <button
              type="button"
              class="ui-menu__item ui-menu__item-index__0-2"
              disabled=""
            >
              <ui-span
                ><span>
                  <ui-text-content
                    ><span class="">Update password</span></ui-text-content
                  >
                </span></ui-span
              >
            </button>
          </li>
          <li>
            <button
              type="button"
              class="ui-menu__item ui-menu__item-index__0-3"
              disabled=""
            >
              <ui-span
                ><span>
                  <ui-text-content
                    ><span class="">Delete</span></ui-text-content
                  >
                </span></ui-span
              >
            </button>
          </li>
        </ul>
      </div>
    </div>
  </details>
</ui-menu>

References

FAQ

Open the menu using javascript

This Boolean attribute indicates whether or not the details — that is, the contents of the <details> element — are currently visible. The default, false, means the details are not visible.

var details = document.getElementById("my-details");
details.open = true;

Toggle the menu using javascript

In addition to the usual events supported by HTML elements, the <details> element supports the toggle event, which is dispatched to the <details> element whenever its state changes between open and closed. It is sent after the state is changed, although if the state changes multiple times before the browser can dispatch the event, the events are coalesced so that only one is sent.

var details = document.getElementById("my-details");

details.addEventListener("toggle", (event) => {
  if (details.open) {
    /_ the element was toggled open _/;
  } else {
    /_ the element was toggled closed _/;
  }
});

Change the width of the menu content

By default - that menu will be as wide as the content - up-to a maximum of 240px. (So if the content is less than 240px it will be smaller). You can set a specific size by overriding the class .ds-menu or by adding an inline style tag.

To override:

Increase max-width

html
Copy
<div class="ds-menu" style="max-width: 400px;"></div>

Set width to an exact size

html
Copy
<div class="ds-menu" style="width: 400px; max-width: 400px;"></div>