Menu

A dropdown on the Popover API. Also fully working on this JavaScript-free page: open one, click outside it, press Escape, open a second one and watch the first close.

Reference

sk-menu

The platform supplies light dismiss, Escape, the top layer, and closing other popovers in the same stack. Positioning uses the implicit anchor that a popovertarget invoker creates, so there is no anchor-name to declare and therefore no per-instance inline style for a strict CSP to reject.

<button class="sk-button" popovertarget="row-menu">Actions</button>

<div class="sk-menu" id="row-menu" popover>
  <p class="sk-menu-label">Group</p>
  <a class="sk-menu-item" href="/edit">Edit</a>
  <hr class="sk-menu-separator">
  <button class="sk-menu-item" data-status="danger"
          popovertarget="row-menu" popovertargetaction="hide">Delete</button>
</div>
AttributeTypeDefaultNotes
popoverboolean attribute-Puts the menu in the top layer and gives it light dismiss.
popovertargetmenu id-On the trigger. Broadly supported - unlike the modal invoker, this needs no fallback.
popovertargetaction"hide" | "show" | "toggle""toggle""hide" on an item button dismisses the menu when it acts.
data-align"end"startHangs from the trigger's trailing edge.
data-side"top"bottomOpens upward. It flips automatically when there is no room, so this is only for when you want it up by default.
position-try-fallbacks-flip-block, flip-inlineWhy a menu on the last row of a table does not open off the bottom of the screen.

Examples

Actions

Items are buttons or links, never a div with a handler - both are focusable and operable from the keyboard with nothing added.

Show markup
<div class="sk-flex sk-items-center sk-gap-3">
  <button class="sk-button" type="button" data-variant="neutral" data-size="md" popovertarget="demo-menu">
    Actions
    <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
      <path d="m6 9 6 6 6-6">
      </path>
    </svg>
  </button>
  <div class="sk-menu" id="demo-menu" popover aria-label="Actions">
    <a class="sk-menu-item" href="#">
      <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
        <path d="M12 5v14">
        </path>
        <path d="M5 12h14">
        </path>
      </svg>
      Duplicate
    </a>
    <a class="sk-menu-item" href="#">
      <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
        <path d="M14 4h6v6">
        </path>
        <path d="M20 4 11 13">
        </path>
        <path d="M18 14v4a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4">
        </path>
      </svg>
      Open in a new tab
    </a>
    <hr class="sk-menu-separator">
    <button type="button" class="sk-menu-item" data-status="danger" popovertarget="demo-menu" popovertargetaction="hide">
      <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
        <path d="M4 7h16">
        </path>
        <path d="M10 11v6">
        </path>
        <path d="M14 11v6">
        </path>
        <path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2l1-12">
        </path>
        <path d="M9 7V5a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2">
        </path>
      </svg>
      Delete
    </button>
  </div>
</div>

Grouped

Labels and separators. The separator is an <hr>, so the split is in the document and not only in the paint.

Sort by


Density


Show markup
<div class="sk-flex sk-items-center sk-gap-3">
  <button class="sk-button" type="button" data-variant="neutral" data-size="md" popovertarget="demo-menu-2">
    View
    <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
      <path d="m6 9 6 6 6-6">
      </path>
    </svg>
  </button>
  <div class="sk-menu" id="demo-menu-2" popover aria-label="View options">
    <p class="sk-menu-label">
      Sort by
    </p>
    <button type="button" class="sk-menu-item" popovertarget="demo-menu-2" popovertargetaction="hide">
      <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
        <path d="M20 6 9 17l-5-5">
        </path>
      </svg>
      Newest first
    </button>
    <button type="button" class="sk-menu-item" popovertarget="demo-menu-2" popovertargetaction="hide">
      Oldest first
    </button>
    <hr class="sk-menu-separator">
    <p class="sk-menu-label">
      Density
    </p>
    <button type="button" class="sk-menu-item" popovertarget="demo-menu-2" popovertargetaction="hide">
      Comfortable
      <span class="sk-menu-item-detail">
        ⌘1
      </span>
    </button>
    <button type="button" class="sk-menu-item" popovertarget="demo-menu-2" popovertargetaction="hide">
      Compact
      <span class="sk-menu-item-detail">
        ⌘2
      </span>
    </button>
    <hr class="sk-menu-separator">
    <button type="button" class="sk-menu-item" disabled>
      Unavailable option
    </button>
  </div>
</div>

Aligned to the end

the trigger is at the far edge
Show markup
<div class="sk-flex sk-justify-between sk-items-center">
  <span class="sink-caption">
    the trigger is at the far edge
  </span>
  <button class="sk-button" type="button" data-variant="neutral" data-size="sm" popovertarget="demo-menu-3">
    Options
    <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
      <path d="m6 9 6 6 6-6">
      </path>
    </svg>
  </button>
  <div class="sk-menu" id="demo-menu-3" popover data-align="end" aria-label="Options">
    <a class="sk-menu-item" href="#">
      Rename
    </a>
    <a class="sk-menu-item" href="#">
      Move
    </a>
    <a class="sk-menu-item" href="#">
      Archive
    </a>
  </div>
</div>

In a table

The reason position-try-fallbacks is there: open the menu on the last row and it flips above the trigger rather than off the bottom of the frame.

Name Actions
Ada Lovelace
Grace Hopper
Alan Turing
Katherine Johnson
Edsger Dijkstra
Show markup
<div class="sk-table-wrap">
  <table class="sk-table" data-density="compact" data-hoverable="true">
    <thead>
      <tr>
        <th scope="col">
          Name
        </th>
        <th scope="col" data-col="actions">
          <span class="sk-visually-hidden">
            Actions
          </span>
        </th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>
          Ada Lovelace
        </td>
        <td data-col="actions">
          <button class="sk-button" type="button" data-variant="quiet" data-size="sm" popovertarget="row-menu-0">
            Actions
            <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
              <path d="m6 9 6 6 6-6">
              </path>
            </svg>
          </button>
          <div class="sk-menu" id="row-menu-0" popover data-align="end" aria-label="Actions for Ada Lovelace">
            <a class="sk-menu-item" href="#">
              Edit
            </a>
            <a class="sk-menu-item" href="#">
              Duplicate
            </a>
            <hr class="sk-menu-separator">
            <button type="button" class="sk-menu-item" data-status="danger" popovertarget="row-menu-0" popovertargetaction="hide">
              Delete
            </button>
          </div>
        </td>
      </tr>
      <tr>
        <td>
          Grace Hopper
        </td>
        <td data-col="actions">
          <button class="sk-button" type="button" data-variant="quiet" data-size="sm" popovertarget="row-menu-1">
            Actions
            <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
              <path d="m6 9 6 6 6-6">
              </path>
            </svg>
          </button>
          <div class="sk-menu" id="row-menu-1" popover data-align="end" aria-label="Actions for Grace Hopper">
            <a class="sk-menu-item" href="#">
              Edit
            </a>
            <a class="sk-menu-item" href="#">
              Duplicate
            </a>
            <hr class="sk-menu-separator">
            <button type="button" class="sk-menu-item" data-status="danger" popovertarget="row-menu-1" popovertargetaction="hide">
              Delete
            </button>
          </div>
        </td>
      </tr>
      <tr>
        <td>
          Alan Turing
        </td>
        <td data-col="actions">
          <button class="sk-button" type="button" data-variant="quiet" data-size="sm" popovertarget="row-menu-2">
            Actions
            <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
              <path d="m6 9 6 6 6-6">
              </path>
            </svg>
          </button>
          <div class="sk-menu" id="row-menu-2" popover data-align="end" aria-label="Actions for Alan Turing">
            <a class="sk-menu-item" href="#">
              Edit
            </a>
            <a class="sk-menu-item" href="#">
              Duplicate
            </a>
            <hr class="sk-menu-separator">
            <button type="button" class="sk-menu-item" data-status="danger" popovertarget="row-menu-2" popovertargetaction="hide">
              Delete
            </button>
          </div>
        </td>
      </tr>
      <tr>
        <td>
          Katherine Johnson
        </td>
        <td data-col="actions">
          <button class="sk-button" type="button" data-variant="quiet" data-size="sm" popovertarget="row-menu-3">
            Actions
            <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
              <path d="m6 9 6 6 6-6">
              </path>
            </svg>
          </button>
          <div class="sk-menu" id="row-menu-3" popover data-align="end" aria-label="Actions for Katherine Johnson">
            <a class="sk-menu-item" href="#">
              Edit
            </a>
            <a class="sk-menu-item" href="#">
              Duplicate
            </a>
            <hr class="sk-menu-separator">
            <button type="button" class="sk-menu-item" data-status="danger" popovertarget="row-menu-3" popovertargetaction="hide">
              Delete
            </button>
          </div>
        </td>
      </tr>
      <tr>
        <td>
          Edsger Dijkstra
        </td>
        <td data-col="actions">
          <button class="sk-button" type="button" data-variant="quiet" data-size="sm" popovertarget="row-menu-4">
            Actions
            <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
              <path d="m6 9 6 6 6-6">
              </path>
            </svg>
          </button>
          <div class="sk-menu" id="row-menu-4" popover data-align="end" aria-label="Actions for Edsger Dijkstra">
            <a class="sk-menu-item" href="#">
              Edit
            </a>
            <a class="sk-menu-item" href="#">
              Duplicate
            </a>
            <hr class="sk-menu-separator">
            <button type="button" class="sk-menu-item" data-status="danger" popovertarget="row-menu-4" popovertargetaction="hide">
              Delete
            </button>
          </div>
        </td>
      </tr>
    </tbody>
  </table>
</div>