Dropdown menu

드롭다운 메뉴

A list of commands that drops open below a button; picking one runs it immediately and closes the list.

Also known as: Select menuAction menuContext menuOverflow menu
···
html
<div class="wrap">
  <button class="trigger" id="mb" aria-haspopup="menu" aria-expanded="false">⋯</button>
  <ul class="menu" id="mn" role="menu">
    <li role="menuitem" tabindex="-1">이름 변경</li>
    <li role="menuitem" tabindex="-1">복제</li>
    <li role="menuitem" tabindex="-1" class="danger">삭제</li>
  </ul>
</div>
css
.wrap{position:relative;display:grid;place-items:center;width:100%;height:100%}
.trigger{width:38px;height:38px;border-radius:9px;border:1px solid var(--line);background:var(--surface);color:var(--fg);font-size:16px;cursor:pointer}
.menu{position:absolute;left:50%;bottom:calc(50% + 26px);transform:translate(-50%,6px);list-style:none;margin:0;
  width:140px;background:var(--surface);border:1px solid var(--line);border-radius:10px;padding:5px;
  box-shadow:0 14px 30px rgba(0,0,0,.2);opacity:0;pointer-events:none;transition:opacity .16s,transform .16s}
.menu[data-open]{opacity:1;pointer-events:auto;transform:translate(-50%,0)}
.menu li{padding:8px 10px;border-radius:6px;font-size:12px;color:var(--fg);cursor:pointer}
.menu li[data-hi]{background:var(--accent);color:#fff}
.menu li.danger{color:#e5484d}
.menu li.danger[data-hi]{background:#e5484d;color:#fff}
js
const mb = document.getElementById('mb'), mn = document.getElementById('mn');
const items = [...mn.querySelectorAll('li')];
function open(v) { mn.toggleAttribute('data-open', v); mb.setAttribute('aria-expanded', String(v)); if (!v) items.forEach(i => i.removeAttribute('data-hi')); }
let auto = true;
mb.addEventListener('click', () => { auto = false; open(mn.getAttribute('data-open') === null); });
document.addEventListener('click', (e) => { if (!mn.contains(e.target) && e.target !== mb) open(false); });
function loop() {
  if (!auto) return;
  open(true);
  let i = 0;
  const hi = setInterval(() => {
    if (!auto) return clearInterval(hi);
    items.forEach((it, idx) => it.toggleAttribute('data-hi', idx === i));
    i++;
    if (i > items.length) { clearInterval(hi); setTimeout(() => { if (auto) { open(false); setTimeout(loop, 900); } }, 300); }
  }, 380);
}
setTimeout(loop, 500);

The trigger gets aria-haspopup="menu" and aria-expanded; the list gets role="menu" and each entry role="menuitem". Up/down arrows move between items, Enter or Space runs one, and typeahead — jumping to the item starting with a pressed letter — is common too.

Easy to confuse with a combobox, but the purpose differs. A dropdown menu has no text input at all; each item is closer to an immediate command — "Copy," "Delete." A combobox is a form control where typing filters candidates, aimed at selecting one value rather than running an action.

A checkable menu item (a "Bold" toggle, say) uses role="menuitemcheckbox".