MeDo

AI 드롭다운 메뉴 생성기.

항목을 설명하면 MeDo가 메뉴 전체를 생성합니다 — 트리거, 패널, 구분선으로 묶은 섹션, 서브메뉴, 화살표 키와 첫 글자 입력 탐색, Escape와 외부 클릭으로 닫기, 닫을 때 트리거로 돌아가는 포커스까지.

드롭다운 메뉴
드롭다운 메뉴

메뉴는 탭 정지점 하나이며, 바로 이 부분을 많이 틀립니다

본능적으로는 모든 항목을 포커스 가능하게 만들어 Tab으로 하나씩 지나가게 하고 싶어집니다. 하지만 ARIA menu 패턴은 그 반대입니다: 메뉴 전체가 탭 정지점 하나이고, 화살표 키가 항목 사이에서 roving tabindex를 이동시키며 Tab은 메뉴를 닫고 벗어납니다. 그래서 12개 항목의 계정 메뉴를 건너뛰는 데 열두 번이 아니라 한 번의 키 입력이면 됩니다. 이는 메뉴에 명시적인 포커스 복원이 필요한 이유도 설명합니다: 포커스가 프로그램적으로 패널 안으로 옮겨졌기 때문에, 트리거로 돌려보내지 않고 닫으면 키보드 사용자는 문서 맨 위에 남겨집니다. 트리거와 패널을 하나의 컴포넌트로 생성하면 두 부분이 동일한 포커스 계약에 맞춰 작성되므로 이 왕복이 온전히 유지됩니다.

템플릿 6개

생성할 수 있는 드롭다운 메뉴 템플릿

모든 템플릿은 스크린샷이 아니라 실제 프롬프트입니다. 어떤 AI 에디터에든 붙여넣거나 MeDo에서 실행해 React + Tailwind 코드를 그대로 받으세요.

BasicAccount Menu

Avatar Trigger With Grouped Actions

The top-right menu every product has. Get the focus round trip right here and the rest of your menus inherit it — closing without returning focus drops keyboard users at the top of the document.

Create an account dropdown menu: a 32px avatar trigger with aria-haspopup="menu" and aria-expanded, and a 240px panel with role="menu" anchored 6px below it. Each row is role="menuitem", 32px tall, with a 16px leading icon. Use a roving tabindex so the whole menu is one tab stop — Tab closes it and leaves rather than walking the items. Enter, Space or Arrow Down opens the menu and focuses the first item; Arrow Up opens it focusing the last. Arrow Down and Up cycle with wrapping, Home and End jump to the ends, typing a letter jumps to the next item starting with it, Escape and outside pointerdown close it, and focus returns to the trigger on every close path. Group items with 1px dividers and style Sign out as a destructive red item in its own group.

MeDo에서 시도하기
Table rowRow Overflow

Three-Dot Menu on a Table Row

Repeated once per row, which makes the trigger label the real problem: twenty buttons all called "More options" tell a screen reader user nothing about which record they are about to delete.

Create a row-level overflow menu for a data table: a 32px icon-only three-dot trigger with aria-haspopup="menu", aria-expanded, and an accessible name that names its record — "More actions for invoice 1042" — so repeated triggers are distinguishable. The panel is role="menu" with Edit, Duplicate and Export, then a divider and a destructive Delete that opens a confirmation dialog and moves focus into it rather than acting immediately. Roving tabindex, Arrow Up and Down with wrapping, Home and End, single-letter type-ahead, Escape and outside pointerdown to close, focus back to the trigger. Close the menu when its ancestor scroll container scrolls, since an anchored panel detaches from a row that has moved.

MeDo에서 시도하기
NestedSubmenu

Parent Items With Nested Panels

One level of nesting, with a hover intent delay. Without the delay, dragging the pointer diagonally to the item you wanted opens and closes three submenus on the way there.

Create a dropdown menu with one level of submenus: the parent item carries aria-haspopup="menu", aria-expanded and a trailing chevron, and its child panel is a separate role="menu" anchored to the parent's right edge, flipping to the left when it would leave the viewport. Open the submenu on Arrow Right or Enter with focus on the first child, and on hover after a 150ms intent delay with a similar grace period before closing so a diagonal pointer path does not toggle three panels. Arrow Left closes the submenu and returns focus to the parent item; Escape closes the whole menu and focuses the trigger. Keep type-ahead scoped to the currently open panel, and do not nest a second level.

MeDo에서 시도하기
TogglesCheckable Items

Menu With Checkbox and Radio Rows

View options and sort order inside a menu. The roles change with the semantics — menuitemcheckbox for independent toggles, menuitemradio in a group for one-of-many — and so does whether the panel closes on select.

Create a view-options dropdown mixing checkable rows: a group of role="menuitemcheckbox" rows with aria-checked for column visibility, and below a divider a group of role="menuitemradio" rows inside role="group" with aria-labelledby a Sort by heading, where exactly one is aria-checked. Keep the panel open when a checkbox row is toggled so several can be set in one pass, and close it after a radio selection since the choice is complete. Reserve the check indicator column at a fixed width so labels do not shift when a state changes. Roving tabindex, Arrow Up and Down with wrapping, Home and End, Space toggles without closing, Enter selects, Escape closes and returns focus to the trigger.

MeDo에서 시도하기
NavigationNav Disclosure

Header Dropdown of Plain Links

Deliberately not a menu. A products dropdown holds links, so role="menu" would collapse them into one tab stop and stop cmd+click from opening a new tab.

Create a navigation dropdown for a marketing header that is a disclosure, not an ARIA menu: a trigger button with aria-expanded and aria-controls, and a panel containing a plain ul of anchor elements — no role="menu" or role="menuitem", so each link stays individually focusable and openable in a new tab with cmd+click or middle click. Tab moves through the links in order rather than a roving tabindex. Open on click and on Arrow Down, close on Escape with focus returning to the trigger, close on outside pointerdown, and close on focusout when focus leaves the panel entirely. Do not open on hover alone on touch devices. Mark the link matching the current route with aria-current="page".

MeDo에서 시도하기
FilterableSearch Menu

Long Menu With a Filter Field

Past roughly fifteen items, single-letter type-ahead stops being enough. Adding a text field changes the contract: the field keeps focus and the highlight moves by aria-activedescendant.

Create a filterable dropdown for a long list: a trigger with aria-haspopup and aria-expanded, and a panel whose first element is a search input that receives focus on open. Because a text field now holds focus, switch from a roving tabindex to the combobox approach — role="listbox" on the list, role="option" on rows, and aria-activedescendant on the input so Arrow Up and Down move the highlight while typing keeps working. Filter as the user types with a 150ms debounce, bold the matched substring, cap the list at 280px with internal scroll, and scroll the active option into view with block nearest. Show a no-matches row rather than an empty panel. Escape clears a non-empty filter first, then closes on a second press with focus returning to the trigger.

MeDo에서 시도하기

드롭다운 메뉴 커스터마이즈 방법

<select>가 아니라 동작 메뉴임을 명시하세요

role="menu"는 각 항목이 명령을 실행한다는 사실을 보조 기술에 알립니다. 항목이 대신 폼 값을 설정한다면 listbox나 네이티브 <select>를 요청하세요. 폼 필드에 메뉴를 쓰면 사용자가 선택지를 기대하는 곳에서 스크린 리더가 명령을 안내하게 됩니다.

서브메뉴의 호버 인텐트 지연을 명시하세요

서브메뉴가 열리기 전 약 150ms 지연과 닫히기 전 비슷한 유예 시간을 요청하세요. 이것이 없으면 부모 목록 위로 포인터를 비스듬히 움직이는 동안 원하던 항목에 도달하기까지 서브메뉴 세 개가 열리고 닫힙니다.

화면 경계를 고려한 위치 지정을 명시적으로 요청하세요

패널이 하단 경계 근처에서는 트리거 위로 뒤집히고, 화면에 남도록 수평으로 이동해야 한다고 말하세요. 우측 상단 아바타에 고정된 메뉴는 고정 오프셋 때문에 항목 절반이 화면 밖으로 렌더링되는 가장 흔한 사례입니다.

파괴적 항목을 분리하세요

로그아웃, 삭제, 접근 권한 취소 같은 동작은 구분선 아래 별도 그룹에 두고 파괴적 색상 처리를 요청하세요. 오클릭을 막는 것은 빨간 글씨가 아니라 일상적인 항목과의 물리적 거리입니다.

드롭다운 메뉴 컴포넌트를 사용하는 사람

SaaS 제품

우측 상단의 아바타 메뉴로, 계정 이메일을 정적 헤더 행으로 표시하고 이어서 프로필과 결제 링크, 팀 서브메뉴, 테마 토글, 그리고 구분선 아래 격리된 로그아웃을 배치합니다.

대시보드 또는 관리 도구

점 세 개 아이콘 버튼 뒤의 행 단위 오버플로 메뉴로 편집, 복제, 내보내기와 파괴적 삭제를 담고, 트리거는 소속 행으로 레이블을 지정해 스크린 리더가 어떤 레코드를 다루는지 안내하게 합니다.

콘텐츠 편집기

그룹화된 항목 유형, 임베드 제공업체 서브메뉴, 첫 글자 입력 점프를 갖춘 블록 삽입 메뉴로, 목록을 아는 사람은 화살표로 훑지 않고 바로 항목에 도달할 수 있습니다.

마케팅 사이트 내비게이션

role="menu" 대신 평범한 링크 목록으로 만든 내비바의 제품 드롭다운으로, 패널이 본래의 내비게이션처럼 동작하고 링크는 개별적으로 포커스 가능하며 새 탭에서도 열 수 있습니다.

웹사이트 유형별 드롭다운 메뉴 패턴

같은 드롭다운 메뉴 컴포넌트를 게시되는 사이트 유형에 맞춰 조정합니다.

01 / 06

SaaS Account Menu

Avatar trigger, the account email as a static non-focusable header row, then profile and billing links, a team submenu and Sign out below a divider. Keep the email row out of the roving tabindex — a label that takes an arrow keypress to skip reads as a broken menu item.

드롭다운 메뉴 스타일과 변형

페이지의 나머지 부분과 어울리는 변형을 골라 바로 생성하세요.

01 / 06

Grouped Action Menu

Rows split into two or three sections by 1px dividers, with the destructive action alone at the bottom. The physical gap is what prevents the misclick on Sign out or Delete — red text alone does not, because the pointer is already moving before the color registers.

React, Next.js, Vue, Svelte에서의 드롭다운 메뉴

React, Next.js, Vue 3, SvelteKit, Astro 또는 순수 HTML — 같은 드롭다운 메뉴을 여섯 가지 방식으로 넣을 수 있습니다.

01 / 06

React Dropdown Menu

Hold the active index in state and derive tabIndex from it — that is the roving tabindex. Keep a ref to the trigger and focus it in the close handler, since the browser will not restore focus for you.

src/components/Menu.tsx

const [open, setOpen] = useState(false)
const [active, setActive] = useState(0)
const triggerRef = useRef(null)

function close() {
  setOpen(false)
  triggerRef.current?.focus()
}

<button ref={triggerRef} aria-haspopup="menu" aria-expanded={open}>
  Account
</button>

드롭다운 메뉴을 프로젝트에 추가하는 방법

드롭다운 메뉴 템플릿을 고르고 프로덕션에 배포하기까지 네 단계.

01~30s

Pick a Menu Template

Answer one question first: do the items run commands or navigate? Actions get the menu templates and their roving tabindex; links get the navigation disclosure, where every anchor stays its own tab stop.

02~10s

Copy the Prompt

Take the prompt into MeDo, Lovable, Bolt, v0 or Cursor and list your real items with the dividers where you want them. Say which item is destructive and which opens a submenu, since both change the generated markup.

03~1min

Generate and Refine

You get React + Tailwind back with a live preview. Follow up in plain English — "add a filter field", "flip above the trigger near the bottom edge", "turn Sort into radio items" — instead of touching the keydown handler.

04~2min

Wire the Actions and Ship

Connect each item to its handler, then verify the focus round trip with the keyboard alone: open, arrow down, Escape, and confirm focus lands back on the trigger rather than the top of the page.

드롭다운 메뉴에 대한 자주 묻는 질문

AI로 드롭다운 메뉴를 생성하는 방법은?

원하는 항목을 나열하고, 어느 항목이 서브메뉴를 여는지 표시하며, 구분선 위치를 알려주세요. MeDo는 트리거, 고정된 패널, 그룹 항목, 키보드 처리를 하나의 컴포넌트로 생성하므로 열기 전부터 화살표 키, Escape, 외부 클릭, 포커스 복원이 연결되어 있습니다.

드롭다운 메뉴와 <select>의 차이는 무엇인가요?

메뉴는 동작을 실행합니다. 항목을 고르면 즉시 무언가가 일어나고 아무것도 저장되지 않습니다. <select>는 폼 값을 담습니다. 옵션을 고르면 나중에 제출될 상태가 바뀝니다. 둘은 서로 다른 role과 서로 다른 키보드 계약을 쓰며, 하나를 다른 하나로 바꿔 쓰는 것이 커스텀 드롭다운에서 가장 흔한 접근성 결함입니다.

내비게이션 드롭다운에 role="menu"를 써야 하나요?

아니요. role="menu"는 애플리케이션형 명령 메뉴를 위한 것이며, 링크 목록에 적용하면 각 링크가 menuitem으로 안내되고 전체가 탭 정지점 하나로 합쳐집니다. 내비게이션 드롭다운은 트리거가 aria-expanded로 토글하는 disclosure 안의 평범한 앵커 목록이어야 합니다. 패널이 내비게이션이라고 MeDo에 알려주면 메뉴 항목 대신 링크를 생성합니다.

드롭다운 메뉴의 키보드 탐색은 어떻게 동작해야 하나요?

Enter, Space 또는 Arrow Down으로 메뉴가 열리고 첫 항목에 포커스가 갑니다. Arrow Up과 Down은 항목 사이를 이동하며 양 끝에서 순환하고, Home과 End는 첫 항목과 마지막 항목으로 이동하며, 글자를 입력하면 그 글자로 시작하는 다음 항목으로 이동합니다. Arrow Right는 서브메뉴를 열고 Arrow Left는 닫으며, Escape나 Tab은 메뉴 전체를 닫고 포커스를 트리거로 돌려보냅니다.

AI가 서브메뉴가 있는 드롭다운 메뉴를 생성할 수 있나요?

네. 중첩 구조를 설명하면 MeDo가 aria-haspopup을 가진 부모 항목, 자식 패널, 호버 인텐트 지연, Arrow Right와 Arrow Left 바인딩을 생성합니다. 가능하면 중첩은 한 단계로 유지하세요. 두 번째 단계는 포인터로 맞추기 어렵고 스크린 리더 사용자에게 설명하기도 어렵습니다.

드롭다운 메뉴는 외부 클릭 시 닫혀야 하나요?

네, 그리고 Escape, 상위 컨테이너의 스크롤, 트리거 재클릭에도 닫혀야 합니다. 외부 리스너는 click이 아니라 pointerdown에 연결해 패널 밖에서 시작된 드래그로도 닫히게 하고, 키보드 사용자가 페이지 맨 위에 남겨지지 않도록 항상 포커스를 트리거로 되돌리세요.