Skip to content
Forms, switch product

Menu

Menu widgets are Interactive Fields (Actions): a button that opens a list of actions, such as the actions of a row. When the user picks one, the menu emits its click event with the action’s value, and closes. Like a button, a menu has no path and puts nothing in the form data.

menu.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.actions.menu({
items: [
{
label: 'Edit',
value: 'edit',
},
{
label: 'Duplicate',
value: 'duplicate',
},
{
separator: true,
},
{
label: 'Delete',
value: 'delete',
},
],
label: 'Actions',
uid: 'cardActions',
onClick: () => 'menuPicked',
}),
gui.inputs.textInput('menuResult', {
hint: 'Pick an action from the menu.',
label: 'Last action',
readonly: true,
}),
];
menu.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "action",
"type": "menu",
"uid": "cardActions",
"label": "Actions",
"on": {
"click": "menuPicked"
},
"props": {
"items": [
{
"label": "Edit",
"value": "edit"
},
{
"label": "Duplicate",
"value": "duplicate"
},
{
"separator": true
},
{
"label": "Delete",
"value": "delete"
}
]
}
},
{
"kind": "input",
"type": "textinput",
"path": "menuResult",
"label": "Last action",
"readonly": true,
"props": {
"hint": "Pick an action from the menu."
}
}
]
}

Use these props to customize your Menu widget.

proptypedescription
itemsarrayRequired. The menu’s items, in order: actions { label, value, disabled? } and separators { separator: true }
ariaLabelstringThe button’s accessible name when it has no label, such as an icon-only button
iconstringAn icon on the button, as on the Button
iconPosition'left' | 'right'The side of the label the icon is on. Defaults to 'left'
placementstringWhere the menu opens next to its button. Defaults to 'bottom-start'
variant'filled' | 'outlined' | 'link'The button’s style. Defaults to 'filled'

The item labels and ariaLabel accept a translation config.

Wire the menu’s click event. In JSON, on: { "click": "<eventName>" } emits that event through your app’s formEvent, and event.detail.value is the picked item’s value. With the DX, onClick takes the event too: unlike a button’s onClick, which gets the form data, a menu’s gets the event, so it can read the value directly.

menu-handler.ts
gui.actions.menu({
label: 'Actions',
items: [
{ label: 'Edit', value: 'edit' },
{ label: 'Delete', value: 'delete' },
],
onClick: (event) => console.log(event.detail.value), // 'edit' or 'delete'
});

Inside a Repeater, the event also says which row the menu is in: see Events.

Use the property variant to style the button as on the Button: filled, the default, outlined or link.

menu.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.actions.menu({
items: [
{
label: 'Edit',
value: 'edit',
},
{
label: 'Duplicate',
value: 'duplicate',
},
{
separator: true,
},
{
label: 'Delete',
value: 'delete',
},
],
variant: 'outlined',
label: 'Outlined',
uid: 'menuOutlined',
}),
gui.actions.menu({
items: [
{
label: 'Edit',
value: 'edit',
},
{
label: 'Duplicate',
value: 'duplicate',
},
{
separator: true,
},
{
label: 'Delete',
value: 'delete',
},
],
variant: 'link',
label: 'Link',
uid: 'menuLink',
}),
];
menu.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "action",
"type": "menu",
"uid": "menuOutlined",
"label": "Outlined",
"props": {
"items": [
{
"label": "Edit",
"value": "edit"
},
{
"label": "Duplicate",
"value": "duplicate"
},
{
"separator": true
},
{
"label": "Delete",
"value": "delete"
}
],
"variant": "outlined"
}
},
{
"kind": "action",
"type": "menu",
"uid": "menuLink",
"label": "Link",
"props": {
"items": [
{
"label": "Edit",
"value": "edit"
},
{
"label": "Duplicate",
"value": "duplicate"
},
{
"separator": true
},
{
"label": "Delete",
"value": "delete"
}
],
"variant": "link"
}
}
]
}

Use the properties icon and iconPosition to add an icon to the button.

menu.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.actions.menu({
items: [
{
label: 'Edit',
value: 'edit',
},
{
label: 'Duplicate',
value: 'duplicate',
},
{
separator: true,
},
{
label: 'Delete',
value: 'delete',
},
],
icon: 'more_vert',
iconPosition: 'right',
label: 'More',
uid: 'menuIcon',
}),
];
menu.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "action",
"type": "menu",
"uid": "menuIcon",
"label": "More",
"props": {
"items": [
{
"label": "Edit",
"value": "edit"
},
{
"label": "Duplicate",
"value": "duplicate"
},
{
"separator": true
},
{
"label": "Delete",
"value": "delete"
}
],
"icon": "more_vert",
"iconPosition": "right"
}
}
]
}

Leave out the label for an icon-only button, such as the “more” button of a row.

menu.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.actions.menu({
items: [
{
label: 'Edit',
value: 'edit',
},
{
label: 'Duplicate',
value: 'duplicate',
},
{
separator: true,
},
{
label: 'Delete',
value: 'delete',
},
],
icon: 'more_vert',
variant: 'outlined',
ariaLabel: 'Row actions',
uid: 'rowActions',
}),
];
menu.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "action",
"type": "menu",
"uid": "rowActions",
"props": {
"items": [
{
"label": "Edit",
"value": "edit"
},
{
"label": "Duplicate",
"value": "duplicate"
},
{
"separator": true
},
{
"label": "Delete",
"value": "delete"
}
],
"icon": "more_vert",
"variant": "outlined",
"ariaLabel": "Row actions"
}
}
]
}

Use the property placement to set where the menu opens: top, bottom, start or end of the button, centered on it, or with -start or -end to line it up with an edge of the button, such as bottom-start, the default, or top-end. Start and end follow the reading direction. When the menu doesn’t fit, it opens on the other side.

menu.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.actions.menu({
items: [
{
label: 'Edit',
value: 'edit',
},
{
label: 'Duplicate',
value: 'duplicate',
},
{
separator: true,
},
{
label: 'Delete',
value: 'delete',
},
],
placement: 'top-start',
label: 'Opens above',
uid: 'menuTop',
}),
];
menu.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "action",
"type": "menu",
"uid": "menuTop",
"label": "Opens above",
"props": {
"items": [
{
"label": "Edit",
"value": "edit"
},
{
"label": "Duplicate",
"value": "duplicate"
},
{
"separator": true
},
{
"label": "Delete",
"value": "delete"
}
],
"placement": "top-start"
}
}
]
}

An item with disabled: true shows in the menu, but the user can’t pick it, and the arrow keys skip it. A menu with disabled: true can’t be opened.

menu.ts
import { gui } from '@golemui/gui-shared';
export default [
gui.actions.menu({
items: [
{
label: 'Edit',
value: 'edit',
},
{
label: 'Archive',
value: 'archive',
disabled: true,
},
{
separator: true,
},
{
label: 'Delete',
value: 'delete',
},
],
label: 'Actions',
uid: 'menuDisabledItem',
}),
gui.actions.menu({
items: [
{
label: 'Edit',
value: 'edit',
},
{
label: 'Duplicate',
value: 'duplicate',
},
{
separator: true,
},
{
label: 'Delete',
value: 'delete',
},
],
label: 'Unavailable',
disabled: true,
uid: 'menuDisabled',
}),
];
menu.json
{
"$schema": "https://golemui.com/schemas/form.schema.json",
"form": [
{
"kind": "action",
"type": "menu",
"uid": "menuDisabledItem",
"label": "Actions",
"props": {
"items": [
{
"label": "Edit",
"value": "edit"
},
{
"label": "Archive",
"value": "archive",
"disabled": true
},
{
"separator": true
},
{
"label": "Delete",
"value": "delete"
}
]
}
},
{
"kind": "action",
"type": "menu",
"uid": "menuDisabled",
"label": "Unavailable",
"disabled": true,
"props": {
"items": [
{
"label": "Edit",
"value": "edit"
},
{
"label": "Duplicate",
"value": "duplicate"
},
{
"separator": true
},
{
"label": "Delete",
"value": "delete"
}
]
}
}
]
}

The menu follows the menu button pattern: Enter, Space or ↓ on the button opens it on the first item, and ↑ on the last. In the menu, the arrow keys move between the items, Home and End go to the ends, and typing moves to the item that starts with the letters typed. Enter or Space picks an item, and Escape closes the menu. Both return the focus to the button.

Menus can be styled as explained in the Styling Guide. The button takes the CSS Variables of the Button.

Following you will find a list with the CSS Variables and a quick description of what you will style.

CSS VariableDescription
--gui-bg-defaultBackground of the menu
--gui-border-defaultBorder of the menu, and the separators
--gui-radius-mdBorder radius of the menu
--gui-shadow-mdShadow of the menu
--gui-bg-surface-hoverBackground of the item under the pointer or focused
--gui-border-focusFocus outline of an item
--gui-text-disabledText of a disabled item
--gui-overlay-durationHow long the menu takes to fade in and out

This is the anatomy of the Menu widget in case you want to use your CSS styles.

menu-anatomy.html
<gui-menu-interactive class="gui-menu-button gui-field">
<div class="gui-widget">
<button
type="button"
id="fieldUid"
class="gui-button gui-button-icon-left"
popovertarget="fieldUid_menu"
aria-haspopup="menu"
>
<span>Actions</span>
</button>
</div>
<gui-menu placement="bottom-start">
<div popover id="fieldUid_menu" role="menu" aria-labelledby="fieldUid">
<button type="button" value="edit" role="menuitem" tabindex="-1">Edit</button>
<button type="button" value="archive" disabled role="menuitem" tabindex="-1">Archive</button>
<hr />
<button type="button" value="delete" role="menuitem" tabindex="-1">Delete</button>
</div>
</gui-menu>
</gui-menu-interactive>