` | Radio option within a RadioGroup. |
| `Sub` | none | Submenu context. Manages submenu open state. |
| `SubTrigger` | `
` | Opens a submenu on hover or keyboard. |
| `SubContent` | `
` | Submenu container. Positioned relative to SubTrigger. |
## ARIA
| Part | Attribute | Value |
| ------------ | ------------------ | ------------------ |
| Trigger | `aria-haspopup` | `menu` |
| Trigger | `aria-expanded` | `true` \| `false` |
| Trigger | `aria-controls` | ID of Content |
| Content | `role` | `menu` |
| Content | `aria-orientation` | `vertical` |
| Item | `role` | `menuitem` |
| CheckboxItem | `role` | `menuitemcheckbox` |
| CheckboxItem | `aria-checked` | `true` \| `false` |
| RadioGroup | `role` | `group` |
| RadioItem | `role` | `menuitemradio` |
| RadioItem | `aria-checked` | `true` \| `false` |
| Group | `role` | `group` |
| Group | `aria-labelledby` | ID of GroupHeading |
| Separator | `role` | `separator` |
| Separator | `aria-orientation` | `horizontal` |
| SubTrigger | `role` | `menuitem` |
| SubTrigger | `aria-haspopup` | `menu` |
| SubTrigger | `aria-expanded` | `true` \| `false` |
| SubTrigger | `aria-controls` | ID of SubContent |
| SubContent | `role` | `menu` |
| SubContent | `aria-orientation` | `vertical` |
## Data Attributes
| Part | Attribute | Values |
| ------------ | ---------------------------------- | -------------------------------------- |
| Trigger | `data-dropdown-menu-trigger` | Always present |
| Trigger | `data-state` | `open` \| `closed` |
| Content | `data-dropdown-menu-content` | Always present |
| Content | `data-state` | `open` \| `closed` |
| Content | `data-side` | `top` \| `right` \| `bottom` \| `left` |
| Content | `data-align` | `start` \| `center` \| `end` |
| Content | `data-starting-style` | Present during open animation |
| Content | `data-ending-style` | Present during close animation |
| Item | `data-dropdown-menu-item` | Always present |
| Item | `data-disabled` | Present when disabled |
| Item | `data-text-value` | Text content for typeahead |
| CheckboxItem | `data-dropdown-menu-checkbox-item` | Always present |
| CheckboxItem | `data-state` | `checked` \| `unchecked` |
| CheckboxItem | `data-disabled` | Present when disabled |
| RadioItem | `data-dropdown-menu-radio-item` | Always present |
| RadioItem | `data-state` | `checked` \| `unchecked` |
| RadioItem | `data-disabled` | Present when disabled |
| SubTrigger | `data-dropdown-menu-sub-trigger` | Always present |
| SubTrigger | `data-state` | `open` \| `closed` |
| SubTrigger | `data-disabled` | Present when disabled |
| SubContent | `data-dropdown-menu-sub-content` | Always present |
| SubContent | `data-state` | `open` \| `closed` |
| Separator | `data-dropdown-menu-separator` | Always present |
## Keyboard
### On Trigger
| Key | Action |
| ------------------------------- | --------------------------- |
| `ArrowDown` / `Enter` / `Space` | Open menu, focus first item |
### On Content
| Key | Action |
| ----------------- | --------------------------------- |
| `ArrowDown` | Move to next item |
| `ArrowUp` | Move to previous item |
| `Home` | Move to first item |
| `End` | Move to last item |
| `Enter` / `Space` | Activate focused item |
| `Escape` | Close menu |
| Character keys | Typeahead — jump to matching item |
### On SubTrigger
| Key | Action |
| ------------------ | ------------ |
| `ArrowRight` (LTR) | Open submenu |
| `Enter` / `Space` | Open submenu |
### On SubContent
| Key | Action |
| ---------------------------- | ------------------------------- |
| `ArrowLeft` (LTR) / `Escape` | Close submenu, focus SubTrigger |
| `ArrowDown` / `ArrowUp` | Navigate items within submenu |
## Motion
The panel uses the standard overlay **state-preset**: `motion="slide-fade"` (default) writes
`data-animation-style`, and the recipe animates it over `data-state` (`dropdown-menu-enter` on open).
The open/close **sema firma** (`emerge`) plays on the content during the hold (see Sema events).
> A previous **opt-in item cascade** (`animation="cascade-slide"`, the rows staggering in/out via a
> `DomCascade`) was **removed** on 2026-06-19 along with the rest of the parallel motion-orchestration
> service — see the retirement note in
> [`MOTION_SERVICE_RFC.md`](../../../eidos/MOTION_SERVICE_RFC.md). Coordinated per-row motion will
> return as a channel of the menu's `emerge.open` firma, materialised by eidos — not a parallel motor.
## Sema events
| Event | Family | Verb | Target | Intent | Sequence | When |
| --------------- | -------- | -------- | --------- | -------- | -------- | ------------------------------------------------- |
| `open` | `emerge` | `open` | `content` | — | `pre` | Menu opens (`handleOpen` central state mutator). |
| `close` | `emerge` | `close` | `content` | — | `pre` | Menu closes (`handleClose`). |
| `commit-select` | `commit` | `select` | `item` | `affirm` | `post` | User activates an item (mouse click or keyboard). |
`open` / `close` use sequence `pre` so the perceptual signal lands at the gesture moment, before the structural flip (the content is still in DOM, the cascade matches `[data-dropdown-menu-content]`). `commit-select` fires from MenuItem `onclick` and `onkeydown` with `e.currentTarget` as fallback target.
**Pack**: [`src/uix/sema/components/dropdown-menu.ts`](../../../sema/components/dropdown-menu.ts):
- `open` → `emerge.soft` (soft chime, gain 0.08).
- `close` → `emerge.exit.soft` (descending pitch + gain 0.05).
- `commit-select` → `form.commit.subtle` + light `tap` haptic. Softer than radio-group because close-emerge + select-commit + downstream-surface fire in quick succession; spreading intensity avoids double-tap fatigue.
## Usage
### Basic
```svelte
Options
Edit
Duplicate
Delete
```
### Checkbox item
```svelte
Show Toolbar
```
### Radio group
```svelte
Light
Dark
System
```
### Submenu
```svelte
Share
Email
Slack
```