Usage
Use a Button or any other component in the default slot of the DropdownMenu.
<script setup lang="ts">
const items = ref([
[
{
label: 'Bitrix24',
avatar: {
src: 'https://github.com/bitrix24.png'
},
type: 'label'
}
],
[
{
label: 'Profile'
},
{
label: 'Billing'
},
{
label: 'Settings',
kbds: [',']
},
{
label: 'Keyboard shortcuts'
}
],
[
{
label: 'Team'
},
{
label: 'Invite users',
children: [
[
{
label: 'Email'
},
{
label: 'Message'
}
],
[
{
label: 'More'
}
]
]
},
{
label: 'New team',
kbds: ['meta', 'n']
}
],
[
{
label: 'GitHub',
to: 'https://github.com/bitrix24/b24ui',
target: '_blank'
},
{
label: 'Support',
to: '/docs/components/dropdown-menu/'
},
{
label: 'API',
disabled: true
}
],
[
{
label: 'Logout',
kbds: ['shift', 'meta', 'q']
}
]
])
</script>
<template>
<B24DropdownMenu :items="items">
<B24Button label="Open" />
</B24DropdownMenu>
</template>
Items
Use the items prop as an array of objects with the following properties:
label?: stringicon?: IconComponentavatar?: AvatarPropskbds?: string[] | KbdProps[]type?: "link" | "label" | "separator" | "checkbox"color?: "air-primary" | "air-primary-success" | "air-primary-alert" | "air-primary-copilot" | "air-primary-warning"checked?: booleandisabled?: booleanslot?: stringonSelect?: (e: Event) => voidonUpdateChecked?: (checked: boolean) => voidchildren?: DropdownMenuItem[] | DropdownMenuItem[][]class?: anyb24ui?: { item?: ClassNameValue, label?: ClassNameValue, separator?: ClassNameValue, itemLeadingIcon?: ClassNameValue, itemLeadingAvatarSize?: ClassNameValue, itemLeadingAvatar?: ClassNameValue, itemLabel?: ClassNameValue, itemLabelExternalIcon?: ClassNameValue, itemTrailing?: ClassNameValue, itemTrailingIcon?: ClassNameValue, itemTrailingKbds?: ClassNameValue, itemTrailingKbdsSize?: ClassNameValue }
You can pass any property from the Link component such as to, target, etc.
<script setup lang="ts">
import type { DropdownMenuItem } from '@bitrix24/b24ui-nuxt'
const items = ref<DropdownMenuItem[][]>([
[
{
label: 'Bitrix24',
avatar: {
src: 'https://github.com/bitrix24.png'
},
type: 'label'
}
],
[
{
label: 'Profile'
},
{
label: 'Billing'
},
{
label: 'Settings',
kbds: [',']
},
{
label: 'Keyboard shortcuts'
}
],
[
{
label: 'Team'
},
{
label: 'Invite users',
children: [
[
{
label: 'Email'
},
{
label: 'Message'
}
],
[
{
label: 'More'
}
]
]
},
{
label: 'New team',
kbds: ['meta', 'n']
}
],
[
{
label: 'GitHub',
to: 'https://github.com/bitrix24/b24ui',
target: '_blank'
},
{
label: 'Support',
to: '/docs/components/dropdown-menu/'
},
{
label: 'API',
disabled: true
}
],
[
{
label: 'Logout',
kbds: ['shift', 'meta', 'q']
}
]
])
</script>
<template>
<B24DropdownMenu :items="items">
<B24Button label="Open" />
</B24DropdownMenu>
</template>
items prop to create separated groups of items.children array of objects with the same properties as the items prop to create a nested menu which can be controlled using the open, defaultOpen and content properties.Content
Use the content prop to control how the DropdownMenu content is rendered, like its align or side for example.
<script setup lang="ts">
import type { DropdownMenuItem } from '@bitrix24/b24ui-nuxt'
const items = ref<DropdownMenuItem[]>([
{
label: 'Profile'
},
{
label: 'Billing'
},
{
label: 'Settings'
}
])
</script>
<template>
<B24DropdownMenu
:items="items"
:content="{
align: 'start',
side: 'bottom',
sideOffset: 8
}"
>
<B24Button label="Open" />
</B24DropdownMenu>
</template>
Arrow
Use the arrow prop to display an arrow on the DropdownMenu.
<script setup lang="ts">
import type { DropdownMenuItem } from '@bitrix24/b24ui-nuxt'
const items = ref<DropdownMenuItem[]>([
{
label: 'Profile'
},
{
label: 'Billing'
},
{
label: 'Settings'
}
])
</script>
<template>
<B24DropdownMenu arrow :items="items">
<B24Button label="Open" />
</B24DropdownMenu>
</template>
Modal
Use the modal prop to control whether the DropdownMenu blocks interaction with outside content. Defaults to true.
<script setup lang="ts">
import type { DropdownMenuItem } from '@bitrix24/b24ui-nuxt'
const items = ref<DropdownMenuItem[]>([
{
label: 'Profile'
},
{
label: 'Billing'
},
{
label: 'Settings'
}
])
</script>
<template>
<B24DropdownMenu
:modal="false"
:items="items"
:b24ui="{
content: 'w-48'
}"
>
<B24Button label="Open" />
</B24DropdownMenu>
</template>
Disabled
Use the disabled prop to disable the DropdownMenu.
<script setup lang="ts">
import type { DropdownMenuItem } from '@bitrix24/b24ui-nuxt'
const items = ref<DropdownMenuItem[]>([
{
label: 'Profile'
},
{
label: 'Billing'
},
{
label: 'Settings'
}
])
</script>
<template>
<B24DropdownMenu
disabled
:items="items"
:ui="{
content: 'w-48'
}"
>
<B24Button label="Open" />
</B24DropdownMenu>
</template>
Examples
With checkbox items
You can use the type property with checkbox and use the checked / onUpdateChecked properties to control the checked state of the item.
checked state of items, it's recommended to wrap your items array inside a computed.With color items
You can use the color property to highlight certain items with a color.
Control open state
You can control the open state by using the default-open prop or the v-model:open directive.
defineShortcuts, you can toggle the DropdownMenu by pressing O.With custom slot
Use the slot property to customize a specific item.
You will have access to the following slots:
#{{ item.slot }}#{{ item.slot }}-leading#{{ item.slot }}-label#{{ item.slot }}-trailing
#item, #item-leading, #item-label and #item-trailing slots to customize all items.With trigger content width
You can expand the content to the full width of its button by adding the w-(--reka-dropdown-menu-trigger-width) class on the b24ui.content and b24ui.viewport slot.
Extract shortcuts
Use the extractShortcuts utility to automatically define shortcuts from menu items with a kbds property. It recursively extracts shortcuts and returns an object compatible with defineShortcuts.
<script setup lang="ts">
import type { DropdownMenuItem } from '@bitrix24/b24ui-nuxt'
const items: DropdownMenuItem[] = [{
label: 'Invite users',
children: [{
label: 'Invite by email',
kbds: ['meta', 'e'],
onSelect() {
console.log('Invite by email clicked')
}
}, {
label: 'Invite by link',
kbds: ['meta', 'i'],
onSelect() {
console.log('Invite by link clicked')
}
}]
}, {
label: 'New team',
kbds: ['meta', 'n'],
onSelect() {
console.log('New team clicked')
}
}]
defineShortcuts(extractShortcuts(items))
</script>
select function of the corresponding item.API
Props
Slots
Emits
Theme
export default defineAppConfig({
b24ui: {
dropdownMenu: {
slots: {
content: 'base-mode bg-(--ui-color-bg-content-primary) shadow-(--popup-window-box-shadow) rounded-(--ui-border-radius-xl) will-change-[opacity] motion-safe:data-[state=open]:animate-[scale-in_100ms_ease-out] motion-safe:data-[state=closed]:animate-[scale-out_100ms_ease-in] origin-(--reka-dropdown-menu-content-transform-origin) font-[family-name:var(--ui-font-family-primary)] relative isolate px-0 py-(--menu-popup-padding) pointer-events-auto',
viewport: 'relative w-full max-h-[40vh] min-w-[192px] overflow-x-hidden overflow-y-auto scrollbar-thin',
arrow: 'fill-(--ui-color-bg-content-primary)',
group: 'grid',
label: 'w-full h-(--popup-window-delimiter-section-height) px-[18px] mt-(--menu-item-block-stack-space) flex flex-row rtl:flex-row-reverse items-center select-none outline-none whitespace-nowrap text-start text-(length:--ui-size-sm) text-(--b24ui-typography-legend-color) font-(--ui-font-weight-normal) after:ms-[10px] after:block after:flex-1 after:min-w-[15px] after:h-px after:bg-(--ui-color-divider-vibrant-default)',
separator: 'my-[8px] mx-[18px] h-[1px] bg-(--ui-color-divider-vibrant-default)',
item: 'group w-full h-[36px] px-[18px] mt-(--menu-item-block-stack-space) relative flex flex-row rtl:flex-row-reverse items-center select-none outline-none whitespace-nowrap cursor-pointer data-disabled:cursor-not-allowed data-disabled:opacity-30 text-start text-(length:--ui-font-size-md) text-(--b24ui-typography-legend-color) hover:text-(--b24ui-typography-label-color) data-highlighted:text-(--b24ui-typography-label-color) data-[state=open]:text-(--b24ui-typography-label-color) hover:bg-(--ui-color-divider-optical-1-alt) data-highlighted:bg-(--ui-color-divider-optical-1-alt) data-[state=open]:bg-(--ui-color-divider-optical-1-alt) transition-colors',
itemLeadingIcon: 'shrink-0 size-[18px] text-(--ui-color-design-plain-content-icon-secondary) group-data-highlighted:text-(--ui-color-accent-main-primary) group-data-[state=open]:text-(--ui-color-accent-main-primary) group-data-[state=checked]:text-(--ui-color-accent-main-primary) transition-colors',
itemLeadingAvatar: 'shrink-0 size-[16px] me-[8px]',
itemLeadingAvatarSize: '2xs',
itemTrailing: 'ml-auto rtl:ml-0 rtl:mr-auto inline-flex gap-1.5 items-center',
itemTrailingIcon: 'shrink-0 size-[24px] text-(--ui-color-accent-main-primary)',
itemTrailingKbds: 'shrink-0 hidden lg:inline-flex items-center gap-0.5',
itemTrailingKbdsSize: 'md',
itemWrapper: 'flex-1 flex flex-col text-start min-w-0',
itemLabel: 'max-w-[240px] truncate -mt-px group-data-[state=checked]:text-(--ui-color-accent-main-primary)',
itemDescription: 'max-w-[240px] truncate -mt-[6px] text-(--b24ui-typography-description-color) text-(length:--ui-font-size-sm)',
itemLabelExternalIcon: 'inline-block size-[16px] text-(--ui-color-design-plain-content-icon-secondary)'
},
variants: {
color: {
'air-primary': {
item: 'style-filled'
},
'air-primary-success': {
item: 'style-filled-success'
},
'air-primary-alert': {
item: 'style-filled-alert'
},
'air-primary-copilot': {
item: 'style-filled-copilot'
},
'air-primary-warning': {
item: 'style-filled-warning'
},
default: {
item: 'style-old-default'
},
danger: {
item: 'style-old-danger'
},
success: {
item: 'style-old-success'
},
warning: {
item: 'style-old-warning'
},
primary: {
item: 'style-old-primary'
},
secondary: {
item: 'style-old-secondary'
},
collab: {
item: 'style-old-collab'
},
ai: {
item: 'style-old-ai'
}
},
active: {
true: {
item: 'text-(--ui-color-accent-main-primary) hover:text-(--ui-color-accent-main-primary)',
itemLeadingIcon: 'text-(--ui-color-accent-main-primary) hover:text-(--ui-color-accent-main-primary) group-data-[state=open]:text-(--ui-color-accent-main-primary)'
},
false: {}
},
loading: {
true: {
itemLeadingIcon: 'animate-spin'
}
}
},
compoundVariants: [],
defaultVariants: {}
}
}
})
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import bitrix24UIPluginVite from '@bitrix24/b24ui-nuxt/vite'
export default defineConfig({
plugins: [
vue(),
bitrix24UIPluginVite({
b24ui: {
dropdownMenu: {
slots: {
content: 'base-mode bg-(--ui-color-bg-content-primary) shadow-(--popup-window-box-shadow) rounded-(--ui-border-radius-xl) will-change-[opacity] motion-safe:data-[state=open]:animate-[scale-in_100ms_ease-out] motion-safe:data-[state=closed]:animate-[scale-out_100ms_ease-in] origin-(--reka-dropdown-menu-content-transform-origin) font-[family-name:var(--ui-font-family-primary)] relative isolate px-0 py-(--menu-popup-padding) pointer-events-auto',
viewport: 'relative w-full max-h-[40vh] min-w-[192px] overflow-x-hidden overflow-y-auto scrollbar-thin',
arrow: 'fill-(--ui-color-bg-content-primary)',
group: 'grid',
label: 'w-full h-(--popup-window-delimiter-section-height) px-[18px] mt-(--menu-item-block-stack-space) flex flex-row rtl:flex-row-reverse items-center select-none outline-none whitespace-nowrap text-start text-(length:--ui-size-sm) text-(--b24ui-typography-legend-color) font-(--ui-font-weight-normal) after:ms-[10px] after:block after:flex-1 after:min-w-[15px] after:h-px after:bg-(--ui-color-divider-vibrant-default)',
separator: 'my-[8px] mx-[18px] h-[1px] bg-(--ui-color-divider-vibrant-default)',
item: 'group w-full h-[36px] px-[18px] mt-(--menu-item-block-stack-space) relative flex flex-row rtl:flex-row-reverse items-center select-none outline-none whitespace-nowrap cursor-pointer data-disabled:cursor-not-allowed data-disabled:opacity-30 text-start text-(length:--ui-font-size-md) text-(--b24ui-typography-legend-color) hover:text-(--b24ui-typography-label-color) data-highlighted:text-(--b24ui-typography-label-color) data-[state=open]:text-(--b24ui-typography-label-color) hover:bg-(--ui-color-divider-optical-1-alt) data-highlighted:bg-(--ui-color-divider-optical-1-alt) data-[state=open]:bg-(--ui-color-divider-optical-1-alt) transition-colors',
itemLeadingIcon: 'shrink-0 size-[18px] text-(--ui-color-design-plain-content-icon-secondary) group-data-highlighted:text-(--ui-color-accent-main-primary) group-data-[state=open]:text-(--ui-color-accent-main-primary) group-data-[state=checked]:text-(--ui-color-accent-main-primary) transition-colors',
itemLeadingAvatar: 'shrink-0 size-[16px] me-[8px]',
itemLeadingAvatarSize: '2xs',
itemTrailing: 'ml-auto rtl:ml-0 rtl:mr-auto inline-flex gap-1.5 items-center',
itemTrailingIcon: 'shrink-0 size-[24px] text-(--ui-color-accent-main-primary)',
itemTrailingKbds: 'shrink-0 hidden lg:inline-flex items-center gap-0.5',
itemTrailingKbdsSize: 'md',
itemWrapper: 'flex-1 flex flex-col text-start min-w-0',
itemLabel: 'max-w-[240px] truncate -mt-px group-data-[state=checked]:text-(--ui-color-accent-main-primary)',
itemDescription: 'max-w-[240px] truncate -mt-[6px] text-(--b24ui-typography-description-color) text-(length:--ui-font-size-sm)',
itemLabelExternalIcon: 'inline-block size-[16px] text-(--ui-color-design-plain-content-icon-secondary)'
},
variants: {
color: {
'air-primary': {
item: 'style-filled'
},
'air-primary-success': {
item: 'style-filled-success'
},
'air-primary-alert': {
item: 'style-filled-alert'
},
'air-primary-copilot': {
item: 'style-filled-copilot'
},
'air-primary-warning': {
item: 'style-filled-warning'
},
default: {
item: 'style-old-default'
},
danger: {
item: 'style-old-danger'
},
success: {
item: 'style-old-success'
},
warning: {
item: 'style-old-warning'
},
primary: {
item: 'style-old-primary'
},
secondary: {
item: 'style-old-secondary'
},
collab: {
item: 'style-old-collab'
},
ai: {
item: 'style-old-ai'
}
},
active: {
true: {
item: 'text-(--ui-color-accent-main-primary) hover:text-(--ui-color-accent-main-primary)',
itemLeadingIcon: 'text-(--ui-color-accent-main-primary) hover:text-(--ui-color-accent-main-primary) group-data-[state=open]:text-(--ui-color-accent-main-primary)'
},
false: {}
},
loading: {
true: {
itemLeadingIcon: 'animate-spin'
}
}
},
compoundVariants: [],
defaultVariants: {}
}
}
})
]
})