Skip to content

Dropdown Menu

A neo-brutalist style dropdown menu built on reka-ui's DropdownMenu primitive, supporting menu items, checkboxes, radio groups, submenus, and keyboard shortcuts.

Demo

Preview

Installation

pnpm dlx brutx-vue@latest add dropdown-menu

Usage

Basic Usage

vue
<script setup>
import {
    DropdownMenu,
    DropdownMenuTrigger,
    DropdownMenuContent,
    DropdownMenuItem,
    DropdownMenuSeparator,
    DropdownMenuLabel,
    DropdownMenuShortcut,
} from 'brutx-ui-vue'
import { Button } from 'brutx-ui-vue'
</script>

<template>
    <DropdownMenu>
        <DropdownMenuTrigger as-child>
            <Button variant="outline">Open Menu</Button>
        </DropdownMenuTrigger>
        <DropdownMenuContent>
            <DropdownMenuLabel>My Account</DropdownMenuLabel>
            <DropdownMenuSeparator />
            <DropdownMenuItem>
                Profile
                <DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
            </DropdownMenuItem>
            <DropdownMenuItem>
                Settings
                <DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
            </DropdownMenuItem>
            <DropdownMenuSeparator />
            <DropdownMenuItem>Log out</DropdownMenuItem>
        </DropdownMenuContent>
    </DropdownMenu>
</template>

Checkbox Items

Use v-model to bind checkbox state, supporting both boolean and 'indeterminate' values.

vue
<script setup>
import { ref } from 'vue'
import {
    DropdownMenu,
    DropdownMenuTrigger,
    DropdownMenuContent,
    DropdownMenuCheckboxItem,
} from 'brutx-ui-vue'
import { Button } from 'brutx-ui-vue'

const showStatusBar = ref(true)
const showActivityBar = ref(false)
</script>

<template>
    <DropdownMenu>
        <DropdownMenuTrigger as-child>
            <Button variant="outline">View</Button>
        </DropdownMenuTrigger>
        <DropdownMenuContent>
            <DropdownMenuCheckboxItem v-model="showStatusBar">
                Status Bar
            </DropdownMenuCheckboxItem>
            <DropdownMenuCheckboxItem v-model="showActivityBar">
                Activity Bar
            </DropdownMenuCheckboxItem>
        </DropdownMenuContent>
    </DropdownMenu>
</template>

Radio Items

vue
<script setup>
import { ref } from 'vue'
import {
    DropdownMenu,
    DropdownMenuTrigger,
    DropdownMenuContent,
    DropdownMenuRadioItem,
    DropdownMenuRadioGroup,
} from 'brutx-ui-vue'
import { Button } from 'brutx-ui-vue'

const position = ref('bottom')
</script>

<template>
    <DropdownMenu>
        <DropdownMenuTrigger as-child>
            <Button variant="outline">Position</Button>
        </DropdownMenuTrigger>
        <DropdownMenuContent>
            <DropdownMenuRadioGroup v-model="position">
                <DropdownMenuRadioItem value="top">Top</DropdownMenuRadioItem>
                <DropdownMenuRadioItem value="bottom">Bottom</DropdownMenuRadioItem>
                <DropdownMenuRadioItem value="left">Left</DropdownMenuRadioItem>
                <DropdownMenuRadioItem value="right">Right</DropdownMenuRadioItem>
            </DropdownMenuRadioGroup>
        </DropdownMenuContent>
    </DropdownMenu>
</template>
vue
<script setup>
import {
    DropdownMenu,
    DropdownMenuTrigger,
    DropdownMenuContent,
    DropdownMenuItem,
    DropdownMenuSub,
    DropdownMenuSubTrigger,
    DropdownMenuSubContent,
} from 'brutx-ui-vue'
import { Button } from 'brutx-ui-vue'
</script>

<template>
    <DropdownMenu>
        <DropdownMenuTrigger as-child>
            <Button variant="outline">Open Menu</Button>
        </DropdownMenuTrigger>
        <DropdownMenuContent>
            <DropdownMenuItem>New Tab</DropdownMenuItem>
            <DropdownMenuSub>
                <DropdownMenuSubTrigger>More Tools</DropdownMenuSubTrigger>
                <DropdownMenuSubContent>
                    <DropdownMenuItem>Save Page</DropdownMenuItem>
                    <DropdownMenuItem>Developer Tools</DropdownMenuItem>
                </DropdownMenuSubContent>
            </DropdownMenuSub>
        </DropdownMenuContent>
    </DropdownMenu>
</template>

Sub-components

ComponentDescription
DropdownMenuRoot component, re-export of reka-ui DropdownMenuRoot
DropdownMenuTriggerButton to open the menu, re-export of reka-ui
DropdownMenuContentDropdown content panel
DropdownMenuItemStandard menu item
DropdownMenuCheckboxItemCheckbox menu item
DropdownMenuRadioItemRadio menu item
DropdownMenuRadioGroupRadio item group, re-export of reka-ui
DropdownMenuLabelSection label
DropdownMenuSeparatorVisual separator
DropdownMenuShortcutKeyboard shortcut hint
DropdownMenuSubSubmenu container, re-export of reka-ui
DropdownMenuSubTriggerSubmenu trigger
DropdownMenuSubContentSubmenu content
DropdownMenuGroupMenu item group, re-export of reka-ui

Props

PropTypeDefaultDescription
sideOffsetnumber6Spacing between menu content and trigger
classstringCustom style class
PropTypeDefaultDescription
insetbooleanWhether to display with indentation (for alignment with submenu triggers)
classstringCustom style class
PropTypeDefaultDescription
v-modelboolean | 'indeterminate'Checkbox state
iconSize'xs' | 'sm' | 'default' | 'lg' | 'xl' | '2xl''default'Checkmark icon size
classstringCustom style class
PropTypeDefaultDescription
valuestring— (required)Radio item value
classstringCustom style class
PropTypeDefaultDescription
insetbooleanWhether to display with indentation
classstringCustom style class
PropTypeDefaultDescription
classstringCustom style class
PropTypeDefaultDescription
classstringCustom style class
PropTypeDefaultDescription
insetbooleanWhether to display with indentation
iconSize'xs' | 'sm' | 'default' | 'lg' | 'xl' | '2xl''default'Expand icon size
classstringCustom style class
PropTypeDefaultDescription
classstringCustom style class

Events

EventPayloadDescription
update:modelValue(value: boolean | 'indeterminate')Triggered when the checkbox state changes

Slots

All custom wrapper components listed below provide a default slot (default) for rendering child content:

ComponentSlotScopeDescription
DropdownMenuContentdefaultDefault slot
DropdownMenuItemdefaultDefault slot
DropdownMenuCheckboxItemdefaultDefault slot
DropdownMenuRadioItemdefaultDefault slot
DropdownMenuLabeldefaultDefault slot
DropdownMenuShortcutdefaultDefault slot
DropdownMenuSubTriggerdefaultDefault slot
DropdownMenuSubContentdefaultDefault slot

Accessibility

  • Keyboard: Supports Space / Enter to open the menu, Escape to close the menu, arrow keys to navigate menu items
  • ARIA Attributes: Automatically manages aria-expanded, aria-haspopup, role="menu" and other accessibility attributes
  • Focus Management: Focus is trapped within the menu when open; focus returns to the trigger when closed
  • Submenu Navigation: Supports expanding and navigating submenus via arrow keys

Brute force builds.