kai-menu
Builds the whole menu, keyboard navigation included, from a plain data tree.
- Shadow DOM
- JSON items tree
- Submenus + checkboxes
- Keyboard navigable
Preview
Section titled “Preview”Build the menu from its items tree, set in JavaScript because arrays can’t be HTML attributes. Each item is an action (id + label, optional icon/shortcut), a heading, a separator, a checkbox (add checked), or a submenu (nest more items). Selecting a leaf fires kai-select with its id.
The trigger is the built-in button (trigger-icon / trigger-label), or your own element in slot="trigger".
<kai-menu trigger-icon="plus" label="Add content"></kai-menu>
<script type="module"> import '@kitn.ai/ui/web-components';
const menu = document.querySelector('kai-menu'); menu.items = [ { heading: true, label: 'Actions' }, { id: 'add-files', label: 'Add files or photos', icon: 'paperclip', shortcut: '⌘U' }, { id: 'add-github', label: 'Add from GitHub', icon: 'github' }, { separator: true }, { id: 'web-search', label: 'Web search', icon: 'globe', checked: true }, ];
menu.addEventListener('kai-select', (e) => { console.log(e.detail); // { id } — or { id, checked } for a checkbox item });</script>Examples
Section titled “Examples”The ”+” menu
Section titled “The ”+” menu”Row overflow
Section titled “Row overflow”Select-style trigger
Section titled “Select-style trigger”The menu builds its own trigger from the trigger-* props; slot your own element for full control of it:
| Slot | Mode | Purpose |
|---|---|---|
| trigger | replace | Your own trigger element; replaces the built-in button driven by the `trigger-icon` / `trigger-label` props. |
<kai-menu> <button slot="trigger" aria-label="Open menu">+</button></kai-menu>| Property | Type | Default | Notes |
|---|---|---|---|
| theme | "light" | "dark" | "auto" | 'auto' | Color mode (`auto` follows prefers-color-scheme). |
| items | — | Tree of menu items. Set as a JS property, not an HTML attribute. | |
| placement | string | — | Optional placement hint (unused by the underlying Dropdown which always positions bottom-start, kept for future extension). |
| triggerIcon | string | — | Built-in trigger: a leading icon (a named icon, an image URL/data-URI, or text). A slotted trigger overrides it. |
| triggerLabel | string | — | Built-in trigger: a text label. |
| triggerIconTrailing | string | — | Built-in trigger: a trailing icon (e.g. `"chevron-down"` for a select look). |
| label | string | — | Accessible name for a trigger with no visible label. Ignored when `triggerLabel` is set. |
| full | boolean | false | Stretch the trigger to the full width of its container (a block row). Attribute: `full`. |
| open | boolean | — | Drive/observe the open state: `el.open = true` or the bare `open` attribute. Listen for `kai-open-change`. |
| defaultOpen | boolean | — | Initial open state on mount (uncontrolled seed). |
| disabled | boolean | — | Disable the trigger: click/keyboard and `show()` no longer open the menu. |
Events
Section titled “Events”| Event | Detail | Notes |
|---|---|---|
| kai-open-change | | The menu opened or closed (by click, keyboard, Escape, outside-click, or a method). |
| kai-select | | A leaf item was selected. Plain: `{ id }`; checkbox: `{ id, checked }` with the NEW state; radio: `{ id, radioGroup }`. |
Methods
Section titled “Methods”| Method | Signature | Notes |
|---|---|---|
| show | (): void | Open it programmatically (no-op while disabled). |
| hide | (): void | Close it programmatically. |
| toggle | (): void | Flip the open state (closes while disabled). |
Composed from
Section titled “Composed from”This element wraps these SolidJS components — reach for them directly when you need finer control than the props expose.
DropdownDropdownTriggerDropdownContentDropdownItemDropdownSeparatorDropdownLabelDropdownCheckboxItemDropdownRadioItemDropdownSubDropdownSubTriggerDropdownSubContentKbd