Dropdown Menu
A menu of actions behind a trigger.
<dropdownmenu.DropdownMenu id="demo-dropdown" class="w-56">
<dropdownmenu.DropdownMenuLabel>My account</dropdownmenu.DropdownMenuLabel>
<dropdownmenu.DropdownMenuSeparator />
<dropdownmenu.DropdownMenuGroup label="Account">
<dropdownmenu.DropdownMenuItem>Profile</dropdownmenu.DropdownMenuItem>
<dropdownmenu.DropdownMenuItem>
Settings
<dropdownmenu.DropdownMenuShortcut>⌘S</dropdownmenu.DropdownMenuShortcut>
</dropdownmenu.DropdownMenuItem>
<dropdownmenu.DropdownMenuLink href={gx.URL("/docs")}>Documentation</dropdownmenu.DropdownMenuLink>
</dropdownmenu.DropdownMenuGroup>
<dropdownmenu.DropdownMenuSeparator />
<dropdownmenu.DropdownMenuCheckboxItem name="status-bar" checked>Status bar</dropdownmenu.DropdownMenuCheckboxItem>
<dropdownmenu.DropdownMenuCheckboxItem name="panel">Panel</dropdownmenu.DropdownMenuCheckboxItem>
<dropdownmenu.DropdownMenuSeparator />
<dropdownmenu.DropdownMenuRadioGroup label="Position">
<dropdownmenu.DropdownMenuRadioItem name="demo-dropdown-position" value="top" checked>
Top
</dropdownmenu.DropdownMenuRadioItem>
<dropdownmenu.DropdownMenuRadioItem name="demo-dropdown-position" value="bottom">
Bottom
</dropdownmenu.DropdownMenuRadioItem>
</dropdownmenu.DropdownMenuRadioGroup>
<dropdownmenu.DropdownMenuSeparator />
<dropdownmenu.DropdownMenuItem variant={dropdownmenu.Destructive}>Sign out</dropdownmenu.DropdownMenuItem>
</dropdownmenu.DropdownMenu>
<dropdownmenu.DropdownMenuTrigger id="demo-dropdown">Open menu</dropdownmenu.DropdownMenuTrigger>Installation
Run the command in the app module.
gx add dropdown-menuThe command also installs button and icons.
The command writes these files.
| File | Path in the app |
|---|---|
DropdownMenu.gx |
ui/dropdown-menu/DropdownMenu.gx |
DropdownMenuCheckboxItem.gx |
ui/dropdown-menu/DropdownMenuCheckboxItem.gx |
DropdownMenuGroup.gx |
ui/dropdown-menu/DropdownMenuGroup.gx |
DropdownMenuItem.gx |
ui/dropdown-menu/DropdownMenuItem.gx |
DropdownMenuLabel.gx |
ui/dropdown-menu/DropdownMenuLabel.gx |
DropdownMenuLink.gx |
ui/dropdown-menu/DropdownMenuLink.gx |
DropdownMenuRadioGroup.gx |
ui/dropdown-menu/DropdownMenuRadioGroup.gx |
DropdownMenuRadioItem.gx |
ui/dropdown-menu/DropdownMenuRadioItem.gx |
DropdownMenuSeparator.gx |
ui/dropdown-menu/DropdownMenuSeparator.gx |
DropdownMenuShortcut.gx |
ui/dropdown-menu/DropdownMenuShortcut.gx |
DropdownMenuSub.gx |
ui/dropdown-menu/DropdownMenuSub.gx |
DropdownMenuSubContent.gx |
ui/dropdown-menu/DropdownMenuSubContent.gx |
DropdownMenuSubTrigger.gx |
ui/dropdown-menu/DropdownMenuSubTrigger.gx |
DropdownMenuTrigger.gx |
ui/dropdown-menu/DropdownMenuTrigger.gx |
DropdownMenu.fixtures.go |
ui/dropdown-menu/DropdownMenu.fixtures.go |
DropdownMenuCheckboxItem.fixtures.go |
ui/dropdown-menu/DropdownMenuCheckboxItem.fixtures.go |
DropdownMenuGroup.fixtures.go |
ui/dropdown-menu/DropdownMenuGroup.fixtures.go |
DropdownMenuItem.fixtures.go |
ui/dropdown-menu/DropdownMenuItem.fixtures.go |
DropdownMenuLabel.fixtures.go |
ui/dropdown-menu/DropdownMenuLabel.fixtures.go |
DropdownMenuLink.fixtures.go |
ui/dropdown-menu/DropdownMenuLink.fixtures.go |
DropdownMenuRadioGroup.fixtures.go |
ui/dropdown-menu/DropdownMenuRadioGroup.fixtures.go |
DropdownMenuRadioItem.fixtures.go |
ui/dropdown-menu/DropdownMenuRadioItem.fixtures.go |
DropdownMenuSeparator.fixtures.go |
ui/dropdown-menu/DropdownMenuSeparator.fixtures.go |
DropdownMenuShortcut.fixtures.go |
ui/dropdown-menu/DropdownMenuShortcut.fixtures.go |
DropdownMenuSub.fixtures.go |
ui/dropdown-menu/DropdownMenuSub.fixtures.go |
DropdownMenuSubContent.fixtures.go |
ui/dropdown-menu/DropdownMenuSubContent.fixtures.go |
DropdownMenuSubTrigger.fixtures.go |
ui/dropdown-menu/DropdownMenuSubTrigger.fixtures.go |
DropdownMenuTrigger.fixtures.go |
ui/dropdown-menu/DropdownMenuTrigger.fixtures.go |
styles.go |
ui/dropdown-menu/styles.go |
Install button and icons first.
Copy each file to its path in the app. Change each import of a registry package to the path of that package in the app.
package dropdownmenu
props {
// Id is the id of the root element. The trigger opens the menu by this id.
Id string
// Align sets the edge of the trigger that the menu lines up with: Center, Start or End.
Align Align = Center
// Class adds classes to the root element.
Class string = ""
// Children is the menu items.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<div id={p.Id} popover="auto" role="menu" data-gx-dismiss data-gx-roving="nowrap" data-gx-place={p.place()} style={p.style()} class={gx.Cx("z-50 min-w-[8rem] overflow-x-hidden overflow-y-auto rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md outline-hidden", motionClass, alignClass[p.align()], p.Class)} {...p.Attrs}>{p.Children}</div>package dropdownmenu
import "github.com/alternayte/gx/registry/icons"
props {
// Name is the name attribute of the checkbox input. A form or a signal reads it.
Name string = ""
// Value is the value that the form sends when the item is checked.
Value string = "on"
// Checked sets the item as checked on the first render.
Checked bool = false
// Disabled turns the item off. The arrow keys pass it.
Disabled bool = false
// Class adds classes to the root element.
Class string = ""
// Children is the label of the item.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<label class={gx.Cx("relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm select-none hover:bg-accent hover:text-accent-foreground has-[:focus]:bg-accent has-[:focus]:text-accent-foreground has-[:disabled]:pointer-events-none has-[:disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", p.Class)} {...p.Attrs}>
<input type="checkbox" role="menuitemcheckbox" tabindex="-1" name={p.Name} value={p.Value} checked={p.Checked} disabled={p.Disabled} class="peer sr-only" {...rovingItem(p.Disabled)} />
<span class="pointer-events-none invisible absolute left-2 flex size-3.5 items-center justify-center peer-checked:visible"><icons.Check class="size-4" /></span>
{p.Children}
</label>package dropdownmenu
props {
// Label is the accessible name of the group. It is not visible.
Label string = ""
// Class adds classes to the root element.
Class string = ""
// Children is the items of the group.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<div role="group" aria-label={p.Label} class={p.Class} {...p.Attrs}>{p.Children}</div>package dropdownmenu
props {
// Variant sets the visual style: Default or Destructive.
Variant Variant = Default
// Inset adds left padding, so the item lines up with the checkbox and radio items.
Inset bool = false
// Disabled turns the item off. The arrow keys pass it.
Disabled bool = false
// Class adds classes to the root element.
Class string = ""
// Children is the content of the item.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<button type="button" role="menuitem" tabindex="-1" disabled={p.Disabled} data-gx-close class={gx.Cx("relative flex w-full cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm outline-hidden select-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground", variantClass[p.variant()], insetClass[p.Inset], p.Class)} {...rovingItem(p.Disabled)} {...p.Attrs}>{p.Children}</button>package dropdownmenu
props {
// Inset adds left padding, so the label lines up with the checkbox and radio items.
Inset bool = false
// Class adds classes to the root element.
Class string = ""
// Children is the text of the label.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<div role="presentation" class={gx.Cx("px-2 py-1.5 text-sm font-medium", insetClass[p.Inset], p.Class)} {...p.Attrs}>{p.Children}</div>package dropdownmenu
props {
// Href is the URL that the link opens.
Href gx.URL
// Class adds classes to the root element.
Class string = ""
// Children is the content of the link.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<a role="menuitem" tabindex="-1" href={p.Href} data-gx-roving-item data-gx-close class={gx.Cx("relative flex w-full cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm no-underline outline-hidden select-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground", p.Class)} {...p.Attrs}>{p.Children}</a>package dropdownmenu
props {
// Label is the accessible name of the group. It is not visible.
Label string = ""
// Class adds classes to the root element.
Class string = ""
// Children is the radio items of the group.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<div role="group" aria-label={p.Label} class={p.Class} {...p.Attrs}>{p.Children}</div>package dropdownmenu
import "github.com/alternayte/gx/registry/icons"
props {
// Name is the name attribute of the radio input. The radio items of one group share
// the same name.
Name string = ""
// Value is the value that the form sends when the item is checked.
Value string = ""
// Checked sets the item as checked on the first render.
Checked bool = false
// Disabled turns the item off. The arrow keys pass it.
Disabled bool = false
// Class adds classes to the root element.
Class string = ""
// Children is the label of the item.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<label class={gx.Cx("relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm select-none hover:bg-accent hover:text-accent-foreground has-[:focus]:bg-accent has-[:focus]:text-accent-foreground has-[:disabled]:pointer-events-none has-[:disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", p.Class)} {...p.Attrs}>
<input type="radio" role="menuitemradio" tabindex="-1" name={p.Name} value={p.Value} checked={p.Checked} disabled={p.Disabled} class="peer sr-only" {...rovingItem(p.Disabled)} />
<span class="pointer-events-none invisible absolute left-2 flex size-3.5 items-center justify-center peer-checked:visible"><icons.Circle class="size-2 *:fill-current" /></span>
{p.Children}
</label>package dropdownmenu
props {
// Class adds classes to the root element.
Class string = ""
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<div role="separator" class={gx.Cx("-mx-1 my-1 h-px bg-border", p.Class)} {...p.Attrs}></div>package dropdownmenu
props {
// Class adds classes to the root element.
Class string = ""
// Children is the text of the keyboard shortcut.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<span class={gx.Cx("ml-auto text-xs tracking-widest text-muted-foreground", p.Class)} {...p.Attrs}>{p.Children}</span>package dropdownmenu
props {
// Class adds classes to the root element.
Class string = ""
// Children is the sub-menu trigger, followed by the sub-menu content.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<div role="none" data-gx-sub class={p.Class} {...p.Attrs}>{p.Children}</div>package dropdownmenu
props {
// Class adds classes to the root element.
Class string = ""
// Children is the list of items of the sub-menu.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<div popover="auto" role="menu" data-gx-roving="nowrap" data-gx-place="right start" class={gx.Cx("z-50 min-w-[8rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-lg outline-hidden", subMotionClass, p.Class)} {...p.Attrs}>{p.Children}</div>package dropdownmenu
import "github.com/alternayte/gx/registry/icons"
props {
// Inset adds left padding, so the trigger lines up with the checkbox and radio items.
Inset bool = false
// Disabled turns the trigger off. The arrow keys pass it.
Disabled bool = false
// Class adds classes to the root element.
Class string = ""
// Children is the label of the trigger. A chevron follows it.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<button type="button" role="menuitem" tabindex="-1" aria-haspopup="menu" aria-expanded="false" disabled={p.Disabled} class={gx.Cx("flex w-full cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm outline-hidden select-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground aria-expanded:bg-accent aria-expanded:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground", insetClass[p.Inset], p.Class)} {...rovingItem(p.Disabled)} {...p.Attrs}>
{p.Children}
<icons.ChevronRight class="ml-auto size-4" />
</button>package dropdownmenu
import "github.com/alternayte/gx/registry/button"
props {
// Id is the id of the menu that the trigger opens.
Id string
// Variant sets the visual style of the button: button.Default, button.Secondary,
// button.Destructive, button.Outline, button.Ghost or button.Link.
Variant button.Variant = button.Outline
// Size sets the height and padding of the button: button.Xs, button.Sm, button.Md, button.Lg,
// or an Icon size for a square button.
Size button.Size = button.Md
// Class adds classes to the root element.
Class string = ""
// Children is the button label.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<button.Button variant={p.variant()} size={p.Size} class={p.Class} attrs={p.attrs()}>{p.Children}</button.Button>package dropdownmenu
import "github.com/alternayte/gx"
var DropdownMenuFixtures = gx.Fixtures[DropdownMenuProps]{
"Menu": {Id: "demo-dropdown", Class: "w-56", Children: gx.Frag(
DropdownMenuLabel(DropdownMenuLabelProps{Children: gx.Text("My account")}),
DropdownMenuSeparator(DropdownMenuSeparatorProps{}),
DropdownMenuGroup(DropdownMenuGroupProps{Label: "Account", Children: gx.Frag(
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Text("Profile")}),
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Frag(
gx.Text("Settings"),
DropdownMenuShortcut(DropdownMenuShortcutProps{Children: gx.Text("⌘S")}),
)}),
DropdownMenuLink(DropdownMenuLinkProps{Href: gx.URL("/docs"), Children: gx.Text("Documentation")}),
)}),
DropdownMenuSeparator(DropdownMenuSeparatorProps{}),
DropdownMenuCheckboxItem(DropdownMenuCheckboxItemProps{Name: "status-bar", Checked: true, Children: gx.Text("Status bar")}),
DropdownMenuCheckboxItem(DropdownMenuCheckboxItemProps{Name: "panel", Children: gx.Text("Panel")}),
DropdownMenuSeparator(DropdownMenuSeparatorProps{}),
DropdownMenuRadioGroup(DropdownMenuRadioGroupProps{Label: "Position", Children: gx.Frag(
DropdownMenuRadioItem(DropdownMenuRadioItemProps{Name: "demo-dropdown-position", Value: "top", Checked: true, Children: gx.Text("Top")}),
DropdownMenuRadioItem(DropdownMenuRadioItemProps{Name: "demo-dropdown-position", Value: "bottom", Children: gx.Text("Bottom")}),
)}),
DropdownMenuSeparator(DropdownMenuSeparatorProps{}),
DropdownMenuItem(DropdownMenuItemProps{Variant: Destructive, Children: gx.Text("Sign out")}),
)},
"End": {Id: "demo-dropdown-end", Align: End, Children: gx.Frag(
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Text("Rename")}),
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Text("Duplicate")}),
DropdownMenuItem(DropdownMenuItemProps{Disabled: true, Children: gx.Text("Archive")}),
DropdownMenuItem(DropdownMenuItemProps{Variant: Destructive, Children: gx.Text("Delete")}),
)},
"Start": {Id: "demo-dropdown-start", Align: Start, Children: gx.Frag(
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Text("Rename")}),
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Text("Duplicate")}),
)},
"Sub": {Id: "demo-dropdown-sub", Class: "w-56", Children: gx.Frag(
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Text("New tab")}),
DropdownMenuSub(DropdownMenuSubProps{Children: gx.Frag(
DropdownMenuSubTrigger(DropdownMenuSubTriggerProps{Children: gx.Text("More tools")}),
DropdownMenuSubContent(DropdownMenuSubContentProps{Class: "w-48", Children: gx.Frag(
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Text("Save page")}),
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Text("Create shortcut")}),
DropdownMenuSeparator(DropdownMenuSeparatorProps{}),
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Text("Developer tools")}),
)}),
)}),
DropdownMenuSeparator(DropdownMenuSeparatorProps{}),
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Text("Print")}),
)},
}package dropdownmenu
import "github.com/alternayte/gx"
var DropdownMenuCheckboxItemFixtures = gx.Fixtures[DropdownMenuCheckboxItemProps]{
"Checked": {Name: "status-bar", Checked: true, Children: gx.Text("Status bar")},
"Unchecked": {Name: "panel", Children: gx.Text("Panel")},
"Disabled": {Name: "activity", Disabled: true, Children: gx.Text("Activity bar")},
}
// DropdownMenuCheckboxItemWrap renders the item inside a menu, as a page uses it.
func DropdownMenuCheckboxItemWrap(n gx.Node) gx.Node {
return gx.El("div", gx.Attrs{{Key: "role", Value: "menu"}, {Key: "class", Value: "w-56"}}, n)
}package dropdownmenu
import "github.com/alternayte/gx"
var DropdownMenuGroupFixtures = gx.Fixtures[DropdownMenuGroupProps]{
"Default": {Label: "Account", Children: gx.Frag(
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Text("Profile")}),
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Text("Billing")}),
)},
}
// DropdownMenuGroupWrap renders the group inside a menu, as a page uses it.
func DropdownMenuGroupWrap(n gx.Node) gx.Node {
return gx.El("div", gx.Attrs{{Key: "role", Value: "menu"}, {Key: "class", Value: "w-56"}}, n)
}package dropdownmenu
import "github.com/alternayte/gx"
var DropdownMenuItemFixtures = gx.Fixtures[DropdownMenuItemProps]{
"Item": {Children: gx.Text("Profile")},
"Inset": {Inset: true, Children: gx.Text("Profile")},
"Destructive": {Variant: Destructive, Children: gx.Text("Delete")},
"Disabled": {Disabled: true, Children: gx.Text("Profile")},
}
// DropdownMenuItemWrap renders the item inside a menu, as a page uses it.
func DropdownMenuItemWrap(n gx.Node) gx.Node {
return gx.El("div", gx.Attrs{{Key: "role", Value: "menu"}, {Key: "class", Value: "w-56"}}, n)
}package dropdownmenu
import "github.com/alternayte/gx"
var DropdownMenuLabelFixtures = gx.Fixtures[DropdownMenuLabelProps]{
"Label": {Children: gx.Text("My account")},
"Inset": {Inset: true, Children: gx.Text("My account")},
}package dropdownmenu
import "github.com/alternayte/gx"
var DropdownMenuLinkFixtures = gx.Fixtures[DropdownMenuLinkProps]{"Link": {Href: gx.URL("/docs"), Children: gx.Text("Documentation")}}
// DropdownMenuLinkWrap renders the item inside a menu, as a page uses it.
func DropdownMenuLinkWrap(n gx.Node) gx.Node {
return gx.El("div", gx.Attrs{{Key: "role", Value: "menu"}, {Key: "class", Value: "w-56"}}, n)
}package dropdownmenu
import "github.com/alternayte/gx"
var DropdownMenuRadioGroupFixtures = gx.Fixtures[DropdownMenuRadioGroupProps]{
"Default": {Label: "Position", Children: gx.Frag(
DropdownMenuRadioItem(DropdownMenuRadioItemProps{Name: "dropdown-menu-group-position", Value: "top", Checked: true, Children: gx.Text("Top")}),
DropdownMenuRadioItem(DropdownMenuRadioItemProps{Name: "dropdown-menu-group-position", Value: "bottom", Children: gx.Text("Bottom")}),
)},
}
// DropdownMenuRadioGroupWrap renders the group inside a menu, as a page uses it.
func DropdownMenuRadioGroupWrap(n gx.Node) gx.Node {
return gx.El("div", gx.Attrs{{Key: "role", Value: "menu"}, {Key: "class", Value: "w-56"}}, n)
}package dropdownmenu
import "github.com/alternayte/gx"
var DropdownMenuRadioItemFixtures = gx.Fixtures[DropdownMenuRadioItemProps]{
"Checked": {Name: "dropdown-menu-item-checked", Value: "top", Checked: true, Children: gx.Text("Top")},
"Unchecked": {Name: "dropdown-menu-item-unchecked", Value: "bottom", Children: gx.Text("Bottom")},
}
// DropdownMenuRadioItemWrap renders the item inside a menu, as a page uses it.
func DropdownMenuRadioItemWrap(n gx.Node) gx.Node {
return gx.El("div", gx.Attrs{{Key: "role", Value: "menu"}, {Key: "class", Value: "w-56"}}, n)
}package dropdownmenu
import "github.com/alternayte/gx"
var DropdownMenuSeparatorFixtures = gx.Fixtures[DropdownMenuSeparatorProps]{"Default": {}}package dropdownmenu
import "github.com/alternayte/gx"
var DropdownMenuShortcutFixtures = gx.Fixtures[DropdownMenuShortcutProps]{"Default": {Children: gx.Text("⌘K")}}package dropdownmenu
import "github.com/alternayte/gx"
var DropdownMenuSubFixtures = gx.Fixtures[DropdownMenuSubProps]{
"Default": {Children: gx.Frag(
DropdownMenuSubTrigger(DropdownMenuSubTriggerProps{Children: gx.Text("More tools")}),
DropdownMenuSubContent(DropdownMenuSubContentProps{Children: gx.Frag(
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Text("Save page")}),
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Text("Create shortcut")}),
)}),
)},
}
// DropdownMenuSubWrap renders the sub-menu inside a menu, as a page uses it.
func DropdownMenuSubWrap(n gx.Node) gx.Node {
return gx.El("div", gx.Attrs{{Key: "role", Value: "menu"}, {Key: "class", Value: "w-56"}}, n)
}package dropdownmenu
import "github.com/alternayte/gx"
var DropdownMenuSubContentFixtures = gx.Fixtures[DropdownMenuSubContentProps]{
"Content": {Class: "w-48", Children: gx.Frag(
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Text("Save page")}),
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Text("Create shortcut")}),
DropdownMenuSeparator(DropdownMenuSeparatorProps{}),
DropdownMenuItem(DropdownMenuItemProps{Children: gx.Text("Developer tools")}),
)},
}
// DropdownMenuSubContentWrap renders the content behind its trigger inside a menu,
// as a page uses it.
func DropdownMenuSubContentWrap(n gx.Node) gx.Node {
return gx.El("div", gx.Attrs{{Key: "role", Value: "menu"}, {Key: "class", Value: "w-56"}},
DropdownMenuSub(DropdownMenuSubProps{Children: gx.Frag(
DropdownMenuSubTrigger(DropdownMenuSubTriggerProps{Children: gx.Text("More tools")}),
n,
)}),
)
}package dropdownmenu
import "github.com/alternayte/gx"
var DropdownMenuSubTriggerFixtures = gx.Fixtures[DropdownMenuSubTriggerProps]{
"Trigger": {Children: gx.Text("More tools")},
"Inset": {Inset: true, Children: gx.Text("More tools")},
"Disabled": {Disabled: true, Children: gx.Text("More tools")},
}
// DropdownMenuSubTriggerWrap renders the trigger inside a menu, as a page uses it.
func DropdownMenuSubTriggerWrap(n gx.Node) gx.Node {
return gx.El("div", gx.Attrs{{Key: "role", Value: "menu"}, {Key: "class", Value: "w-56"}}, n)
}package dropdownmenu
import (
"github.com/alternayte/gx"
"github.com/alternayte/gx/registry/button"
)
var DropdownMenuTriggerFixtures = gx.Fixtures[DropdownMenuTriggerProps]{
"Default": {Id: "demo-dropdown", Children: gx.Text("Open menu")},
"Ghost": {Id: "demo-dropdown-end", Variant: button.Ghost, Size: button.Sm, Class: "ml-32", Children: gx.Text("Open at the end")},
"Start": {Id: "demo-dropdown-start", Variant: button.Secondary, Children: gx.Text("Open at the start")},
"Sub": {Id: "demo-dropdown-sub", Children: gx.Text("Open with a sub-menu")},
}package dropdownmenu
import (
"github.com/alternayte/gx"
"github.com/alternayte/gx/registry/button"
)
// Align is the edge of the trigger that the menu lines up with.
type Align string
// The alignments of dropdownmenu.DropdownMenu.
const (
Center Align = "center"
Start Align = "start"
End Align = "end"
)
// The menu zooms from the edge that touches the trigger. The overlay module
// writes data-side: a menu that flips opens above the trigger.
var alignClass = gx.Enum[Align]{
Center: "origin-top data-[side=top]:origin-bottom",
Start: "origin-top-left data-[side=top]:origin-bottom-left",
End: "origin-top-right data-[side=top]:origin-bottom-right",
}
var alignStyle = gx.Enum[Align]{
Center: "justify-self: anchor-center",
Start: "left: anchor(left)",
End: "right: anchor(right)",
}
// align returns the alignment of one menu; a zero value is Center.
func (p DropdownMenuProps) align() Align {
if p.Align == "" {
return Center
}
return p.Align
}
// style anchors the menu below its trigger for a page whose scripts did not
// run. The overlay module then writes the measured place.
func (p DropdownMenuProps) style() gx.Style {
return gx.Style("position-anchor: --gx-menu-" + p.Id + "; inset: auto; margin: 0.25rem 0 0; top: anchor(bottom); " + alignStyle[p.align()])
}
// place tells the overlay module where the menu goes: below the trigger,
// 4px away, and inside the viewport.
func (p DropdownMenuProps) place() string {
return "bottom " + string(p.align()) + " 4"
}
// variant returns the button variant of one trigger; a zero value is
// button.Outline.
func (p DropdownMenuTriggerProps) variant() button.Variant {
if p.Variant == "" {
return button.Outline
}
return p.Variant
}
// attrs wires the trigger to its menu and names it as the anchor.
func (p DropdownMenuTriggerProps) attrs() gx.Attrs {
return gx.JoinAttrs(gx.Attrs{
{Key: "popovertarget", Value: p.Id},
{Key: "aria-haspopup", Value: "menu"},
{Key: "style", Value: "anchor-name: --gx-menu-" + p.Id, Kind: gx.AttrStyle},
}, p.Attrs)
}
// Variant is the visual style of a menu item.
type Variant string
// The variants of dropdownmenu.DropdownMenuItem.
const (
Default Variant = "default"
Destructive Variant = "destructive"
)
var variantClass = gx.Enum[Variant]{
Default: "",
Destructive: "text-destructive hover:bg-destructive/10 hover:text-destructive focus:bg-destructive/10 focus:text-destructive dark:hover:bg-destructive/20 dark:focus:bg-destructive/20 *:[svg]:text-destructive!",
}
// variant returns the variant of one item; a zero value is Default.
func (p DropdownMenuItemProps) variant() Variant {
if p.Variant == "" {
return Default
}
return p.Variant
}
// insetClass lines an item or a label up with the checkbox and radio items.
var insetClass = map[bool]string{
true: "pl-8",
false: "",
}
// rovingItem marks an item for the roving tabindex of its menu. A disabled
// item is not marked, so the arrow keys pass it.
func rovingItem(disabled bool) gx.Attrs {
return gx.Attrs{gx.Bool("data-gx-roving-item", !disabled)}
}
// motionClass fades and zooms the menu from 95% and slides it 2 units from
// the trigger, from below when the menu took the top side. Safari 26.0 never ends a display transition on an element
// that CSS anchor positioning places, which leaves a closed menu rendered.
// The @supports test matches every engine but WebKit, so Safari closes the
// menu at once and still animates the enter.
const motionClass = "opacity-0 scale-95 transition-[opacity,scale,translate,overlay,display] not-supports-[font:-apple-system-body]:transition-discrete duration-150 open:opacity-100 open:scale-100 starting:open:opacity-0 starting:open:scale-95 starting:open:-translate-y-2 data-[side=top]:starting:open:translate-y-2 motion-reduce:transition-none"
// subMotionClass fades and zooms the content of a sub-menu from 95% and
// slides it 2 units from its trigger. The overlay module writes data-side:
// content that flips to the left slides from the right.
const subMotionClass = "origin-top-left opacity-0 scale-95 transition-[opacity,scale,translate,overlay,display] transition-discrete duration-150 open:opacity-100 open:scale-100 starting:open:opacity-0 starting:open:scale-95 starting:open:-translate-x-2 data-[side=left]:origin-top-right data-[side=left]:starting:open:translate-x-2 motion-reduce:transition-none"The theme must define these tokens: --border, --popover, --popover-foreground, --accent, --accent-foreground, --muted-foreground, --destructive.
Usage
<dropdownmenu.DropdownMenuTrigger id="account">Account</dropdownmenu.DropdownMenuTrigger>
<dropdownmenu.DropdownMenu id="account" class="w-56">
<dropdownmenu.DropdownMenuLabel>My account</dropdownmenu.DropdownMenuLabel>
<dropdownmenu.DropdownMenuSeparator />
<dropdownmenu.DropdownMenuGroup label="Account">
<dropdownmenu.DropdownMenuLink href={gx.URL("/profile")}>Profile</dropdownmenu.DropdownMenuLink>
<dropdownmenu.DropdownMenuItem>
Settings
<dropdownmenu.DropdownMenuShortcut>⌘S</dropdownmenu.DropdownMenuShortcut>
</dropdownmenu.DropdownMenuItem>
</dropdownmenu.DropdownMenuGroup>
<dropdownmenu.DropdownMenuSeparator />
<dropdownmenu.DropdownMenuCheckboxItem name="status-bar" checked={true}>Status bar</dropdownmenu.DropdownMenuCheckboxItem>
<dropdownmenu.DropdownMenuRadioGroup label="Position">
<dropdownmenu.DropdownMenuRadioItem name="position" value="top" checked={true}>Top</dropdownmenu.DropdownMenuRadioItem>
<dropdownmenu.DropdownMenuRadioItem name="position" value="bottom">Bottom</dropdownmenu.DropdownMenuRadioItem>
</dropdownmenu.DropdownMenuRadioGroup>
<dropdownmenu.DropdownMenuSeparator />
<dropdownmenu.DropdownMenuSub>
<dropdownmenu.DropdownMenuSubTrigger>Invite users</dropdownmenu.DropdownMenuSubTrigger>
<dropdownmenu.DropdownMenuSubContent>
<dropdownmenu.DropdownMenuItem>Email</dropdownmenu.DropdownMenuItem>
<dropdownmenu.DropdownMenuItem>Message</dropdownmenu.DropdownMenuItem>
</dropdownmenu.DropdownMenuSubContent>
</dropdownmenu.DropdownMenuSub>
<dropdownmenu.DropdownMenuSeparator />
<dropdownmenu.DropdownMenuItem variant={dropdownmenu.Destructive}>Sign out</dropdownmenu.DropdownMenuItem>
</dropdownmenu.DropdownMenu>The menu uses the native Popover API. The trigger is a button.Button; Variant and Size select its style, and the default is button.Outline. Align lines the menu up with the trigger: dropdownmenu.Center (default), dropdownmenu.Start or dropdownmenu.End.
The menu opens below the trigger. It flips above the trigger when the space below is too small, and it shifts along the trigger to stay 8px inside the viewport. data-side on the menu names the side it took.
A checkbox item and a radio item are native inputs. They carry Name and Value, so a form or a signal reads them. They keep the menu open. An item has Inset, Disabled and the Destructive variant.
The menu fades and zooms in and out. Safari shows the enter transition only. A user who asks for reduced motion gets no transition.
DropdownMenuSub holds one DropdownMenuSubTrigger and one DropdownMenuSubContent, in that order. The sub-menu opens to the right of its trigger, or to the left when the right side is too small. It opens on a click and after the pointer rests on the trigger. It stays open while the pointer moves toward it. An item of a sub-menu closes the whole menu. The trigger has Inset and Disabled.
Examples
DropdownMenu: Menu
<dropdownmenu.DropdownMenu id="demo-dropdown" class="w-56">
<dropdownmenu.DropdownMenuLabel>My account</dropdownmenu.DropdownMenuLabel>
<dropdownmenu.DropdownMenuSeparator />
<dropdownmenu.DropdownMenuGroup label="Account">
<dropdownmenu.DropdownMenuItem>Profile</dropdownmenu.DropdownMenuItem>
<dropdownmenu.DropdownMenuItem>
Settings
<dropdownmenu.DropdownMenuShortcut>⌘S</dropdownmenu.DropdownMenuShortcut>
</dropdownmenu.DropdownMenuItem>
<dropdownmenu.DropdownMenuLink href={gx.URL("/docs")}>Documentation</dropdownmenu.DropdownMenuLink>
</dropdownmenu.DropdownMenuGroup>
<dropdownmenu.DropdownMenuSeparator />
<dropdownmenu.DropdownMenuCheckboxItem name="status-bar" checked>Status bar</dropdownmenu.DropdownMenuCheckboxItem>
<dropdownmenu.DropdownMenuCheckboxItem name="panel">Panel</dropdownmenu.DropdownMenuCheckboxItem>
<dropdownmenu.DropdownMenuSeparator />
<dropdownmenu.DropdownMenuRadioGroup label="Position">
<dropdownmenu.DropdownMenuRadioItem name="demo-dropdown-position" value="top" checked>
Top
</dropdownmenu.DropdownMenuRadioItem>
<dropdownmenu.DropdownMenuRadioItem name="demo-dropdown-position" value="bottom">
Bottom
</dropdownmenu.DropdownMenuRadioItem>
</dropdownmenu.DropdownMenuRadioGroup>
<dropdownmenu.DropdownMenuSeparator />
<dropdownmenu.DropdownMenuItem variant={dropdownmenu.Destructive}>Sign out</dropdownmenu.DropdownMenuItem>
</dropdownmenu.DropdownMenu>
<dropdownmenu.DropdownMenuTrigger id="demo-dropdown">Open menu</dropdownmenu.DropdownMenuTrigger>DropdownMenu: End
<dropdownmenu.DropdownMenu id="demo-dropdown-end" align={dropdownmenu.End}>
<dropdownmenu.DropdownMenuItem>Rename</dropdownmenu.DropdownMenuItem>
<dropdownmenu.DropdownMenuItem>Duplicate</dropdownmenu.DropdownMenuItem>
<dropdownmenu.DropdownMenuItem disabled>Archive</dropdownmenu.DropdownMenuItem>
<dropdownmenu.DropdownMenuItem variant={dropdownmenu.Destructive}>Delete</dropdownmenu.DropdownMenuItem>
</dropdownmenu.DropdownMenu>
<dropdownmenu.DropdownMenuTrigger id="demo-dropdown-end" variant={button.Ghost} size={button.Sm} class="ml-32">
Open at the end
</dropdownmenu.DropdownMenuTrigger>DropdownMenu: Start
<dropdownmenu.DropdownMenu id="demo-dropdown-start" align={dropdownmenu.Start}>
<dropdownmenu.DropdownMenuItem>Rename</dropdownmenu.DropdownMenuItem>
<dropdownmenu.DropdownMenuItem>Duplicate</dropdownmenu.DropdownMenuItem>
</dropdownmenu.DropdownMenu>
<dropdownmenu.DropdownMenuTrigger id="demo-dropdown-start" variant={button.Secondary}>
Open at the start
</dropdownmenu.DropdownMenuTrigger>DropdownMenu: Sub
<dropdownmenu.DropdownMenu id="demo-dropdown-sub" class="w-56">
<dropdownmenu.DropdownMenuItem>New tab</dropdownmenu.DropdownMenuItem>
<dropdownmenu.DropdownMenuSub>
<dropdownmenu.DropdownMenuSubTrigger>More tools</dropdownmenu.DropdownMenuSubTrigger>
<dropdownmenu.DropdownMenuSubContent class="w-48">
<dropdownmenu.DropdownMenuItem>Save page</dropdownmenu.DropdownMenuItem>
<dropdownmenu.DropdownMenuItem>Create shortcut</dropdownmenu.DropdownMenuItem>
<dropdownmenu.DropdownMenuSeparator />
<dropdownmenu.DropdownMenuItem>Developer tools</dropdownmenu.DropdownMenuItem>
</dropdownmenu.DropdownMenuSubContent>
</dropdownmenu.DropdownMenuSub>
<dropdownmenu.DropdownMenuSeparator />
<dropdownmenu.DropdownMenuItem>Print</dropdownmenu.DropdownMenuItem>
</dropdownmenu.DropdownMenu>
<dropdownmenu.DropdownMenuTrigger id="demo-dropdown-sub">Open with a sub-menu</dropdownmenu.DropdownMenuTrigger>DropdownMenuCheckboxItem: Checked
<dropdownmenu.DropdownMenuCheckboxItem name="status-bar" checked>Status bar</dropdownmenu.DropdownMenuCheckboxItem>DropdownMenuCheckboxItem: Unchecked
<dropdownmenu.DropdownMenuCheckboxItem name="panel">Panel</dropdownmenu.DropdownMenuCheckboxItem>DropdownMenuCheckboxItem: Disabled
<dropdownmenu.DropdownMenuCheckboxItem name="activity" disabled>Activity bar</dropdownmenu.DropdownMenuCheckboxItem>DropdownMenuGroup: Default
<dropdownmenu.DropdownMenuGroup label="Account">
<dropdownmenu.DropdownMenuItem>Profile</dropdownmenu.DropdownMenuItem>
<dropdownmenu.DropdownMenuItem>Billing</dropdownmenu.DropdownMenuItem>
</dropdownmenu.DropdownMenuGroup>DropdownMenuItem: Item
<dropdownmenu.DropdownMenuItem>Profile</dropdownmenu.DropdownMenuItem>DropdownMenuItem: Inset
<dropdownmenu.DropdownMenuItem inset>Profile</dropdownmenu.DropdownMenuItem>DropdownMenuItem: Destructive
<dropdownmenu.DropdownMenuItem variant={dropdownmenu.Destructive}>Delete</dropdownmenu.DropdownMenuItem>DropdownMenuItem: Disabled
<dropdownmenu.DropdownMenuItem disabled>Profile</dropdownmenu.DropdownMenuItem>DropdownMenuLabel: Label
<dropdownmenu.DropdownMenuLabel>My account</dropdownmenu.DropdownMenuLabel>DropdownMenuLabel: Inset
<dropdownmenu.DropdownMenuLabel inset>My account</dropdownmenu.DropdownMenuLabel>DropdownMenuLink: Link
<dropdownmenu.DropdownMenuLink href={gx.URL("/docs")}>Documentation</dropdownmenu.DropdownMenuLink>DropdownMenuRadioGroup: Default
<dropdownmenu.DropdownMenuRadioGroup label="Position">
<dropdownmenu.DropdownMenuRadioItem name="dropdown-menu-group-position" value="top" checked>
Top
</dropdownmenu.DropdownMenuRadioItem>
<dropdownmenu.DropdownMenuRadioItem name="dropdown-menu-group-position" value="bottom">
Bottom
</dropdownmenu.DropdownMenuRadioItem>
</dropdownmenu.DropdownMenuRadioGroup>DropdownMenuRadioItem: Checked
<dropdownmenu.DropdownMenuRadioItem name="dropdown-menu-item-checked" value="top" checked>
Top
</dropdownmenu.DropdownMenuRadioItem>DropdownMenuRadioItem: Unchecked
<dropdownmenu.DropdownMenuRadioItem name="dropdown-menu-item-unchecked" value="bottom">
Bottom
</dropdownmenu.DropdownMenuRadioItem>DropdownMenuSeparator: Default
<dropdownmenu.DropdownMenuSeparator />DropdownMenuShortcut: Default
<dropdownmenu.DropdownMenuShortcut>⌘K</dropdownmenu.DropdownMenuShortcut>DropdownMenuSub: Default
<dropdownmenu.DropdownMenuSub>
<dropdownmenu.DropdownMenuSubTrigger>More tools</dropdownmenu.DropdownMenuSubTrigger>
<dropdownmenu.DropdownMenuSubContent>
<dropdownmenu.DropdownMenuItem>Save page</dropdownmenu.DropdownMenuItem>
<dropdownmenu.DropdownMenuItem>Create shortcut</dropdownmenu.DropdownMenuItem>
</dropdownmenu.DropdownMenuSubContent>
</dropdownmenu.DropdownMenuSub>DropdownMenuSubContent: Content
<dropdownmenu.DropdownMenuSubContent class="w-48">
<dropdownmenu.DropdownMenuItem>Save page</dropdownmenu.DropdownMenuItem>
<dropdownmenu.DropdownMenuItem>Create shortcut</dropdownmenu.DropdownMenuItem>
<dropdownmenu.DropdownMenuSeparator />
<dropdownmenu.DropdownMenuItem>Developer tools</dropdownmenu.DropdownMenuItem>
</dropdownmenu.DropdownMenuSubContent>DropdownMenuSubTrigger: Trigger
<dropdownmenu.DropdownMenuSubTrigger>More tools</dropdownmenu.DropdownMenuSubTrigger>DropdownMenuSubTrigger: Inset
<dropdownmenu.DropdownMenuSubTrigger inset>More tools</dropdownmenu.DropdownMenuSubTrigger>DropdownMenuSubTrigger: Disabled
<dropdownmenu.DropdownMenuSubTrigger disabled>More tools</dropdownmenu.DropdownMenuSubTrigger>API reference
A tag sets a prop by its name with a lower-case first letter: Class is class.
dropdownmenu.DropdownMenu
| Prop | Type | Default | Description |
|---|---|---|---|
Id |
string |
Required | Id is the id of the root element. The trigger opens the menu by this id. |
Align |
Align |
Center |
Align sets the edge of the trigger that the menu lines up with: Center, Start or End. |
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the menu items. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
dropdownmenu.DropdownMenuCheckboxItem
| Prop | Type | Default | Description |
|---|---|---|---|
Name |
string |
"" |
Name is the name attribute of the checkbox input. A form or a signal reads it. |
Value |
string |
"on" |
Value is the value that the form sends when the item is checked. |
Checked |
bool |
false |
Checked sets the item as checked on the first render. |
Disabled |
bool |
false |
Disabled turns the item off. The arrow keys pass it. |
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the label of the item. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
dropdownmenu.DropdownMenuGroup
| Prop | Type | Default | Description |
|---|---|---|---|
Label |
string |
"" |
Label is the accessible name of the group. It is not visible. |
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the items of the group. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
dropdownmenu.DropdownMenuItem
| Prop | Type | Default | Description |
|---|---|---|---|
Variant |
Variant |
Default |
Variant sets the visual style: Default or Destructive. |
Inset |
bool |
false |
Inset adds left padding, so the item lines up with the checkbox and radio items. |
Disabled |
bool |
false |
Disabled turns the item off. The arrow keys pass it. |
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the content of the item. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
dropdownmenu.DropdownMenuLabel
| Prop | Type | Default | Description |
|---|---|---|---|
Inset |
bool |
false |
Inset adds left padding, so the label lines up with the checkbox and radio items. |
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the text of the label. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
dropdownmenu.DropdownMenuLink
| Prop | Type | Default | Description |
|---|---|---|---|
Href |
gx.URL |
Required | Href is the URL that the link opens. |
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the content of the link. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
dropdownmenu.DropdownMenuRadioGroup
| Prop | Type | Default | Description |
|---|---|---|---|
Label |
string |
"" |
Label is the accessible name of the group. It is not visible. |
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the radio items of the group. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
dropdownmenu.DropdownMenuRadioItem
| Prop | Type | Default | Description |
|---|---|---|---|
Name |
string |
"" |
Name is the name attribute of the radio input. The radio items of one group share the same name. |
Value |
string |
"" |
Value is the value that the form sends when the item is checked. |
Checked |
bool |
false |
Checked sets the item as checked on the first render. |
Disabled |
bool |
false |
Disabled turns the item off. The arrow keys pass it. |
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the label of the item. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
dropdownmenu.DropdownMenuSeparator
| Prop | Type | Default | Description |
|---|---|---|---|
Class |
string |
"" |
Class adds classes to the root element. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
dropdownmenu.DropdownMenuShortcut
| Prop | Type | Default | Description |
|---|---|---|---|
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the text of the keyboard shortcut. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
dropdownmenu.DropdownMenuSub
| Prop | Type | Default | Description |
|---|---|---|---|
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the sub-menu trigger, followed by the sub-menu content. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
dropdownmenu.DropdownMenuSubContent
| Prop | Type | Default | Description |
|---|---|---|---|
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the list of items of the sub-menu. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
dropdownmenu.DropdownMenuSubTrigger
| Prop | Type | Default | Description |
|---|---|---|---|
Inset |
bool |
false |
Inset adds left padding, so the trigger lines up with the checkbox and radio items. |
Disabled |
bool |
false |
Disabled turns the trigger off. The arrow keys pass it. |
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the label of the trigger. A chevron follows it. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
dropdownmenu.DropdownMenuTrigger
| Prop | Type | Default | Description |
|---|---|---|---|
Id |
string |
Required | Id is the id of the menu that the trigger opens. |
Variant |
button.Variant |
button.Outline |
Variant sets the visual style of the button: button.Default, button.Secondary, button.Destructive, button.Outline, button.Ghost or button.Link. |
Size |
button.Size |
button.Md |
Size sets the height and padding of the button: button.Xs, button.Sm, button.Md, button.Lg, or an Icon size for a square button. |
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the button label. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
Do and do not
Do
- Give the menu and the trigger the same
Id. - Put the menu directly after its trigger in the markup.
- Give the radio items of one group the same
Name. - Put destructive actions last, after a separator.
Don't
- Do not use a dropdown menu as a select control. Use
select. - Do not put a
DropdownMenuin anotherDropdownMenu. UseDropdownMenuSub. - Do not put an element between the trigger and the content of a sub-menu.
Keyboard
| Key | Action |
|---|---|
| Enter, Space | Opens the menu from the trigger. |
| Down | Opens the menu from the trigger and moves to the first item. |
| Up, Down | Moves through the items. A disabled item is passed. |
| Home, End | Moves to the first or last item. |
| A letter | Moves to the next item that starts with the typed text. |
| Enter | Runs the focused item and closes the menu. Toggles a checkbox or radio item. |
| Space | Runs the focused item. Toggles a checkbox or radio item. |
| Right, Enter, Space | On a sub-menu trigger, opens the sub-menu and moves to its first item. |
| Left, Escape | In a sub-menu, closes it and returns focus to its trigger. |
| Escape | Closes the menu and returns focus to the trigger. |