Usage
Use the NavigationMenu component to display a list of links horizontally or vertically.
{
"wait": "Loading client-side content..."
}Items
Use the items prop as an array of objects with the following properties:
label?: stringicon?: IconComponentavatar?: AvatarPropsbadge?: string | number | BadgePropshint?: stringtooltip?: TooltipPropstrailingIcon?: IconComponenttype?: 'label' | 'trigger' | 'link'defaultOpen?: booleanopen?: booleanvalue?: stringdisabled?: booleanslot?: stringviewportRtl?: booleanonSelect?: (e: Event) => voidchildren?: NavigationMenuChildItem[]class?: anyb24ui?: { linkLeadingAvatarSize?: ClassNameValue, linkLeadingAvatar?: ClassNameValue, linkLeadingIcon?: ClassNameValue, linkLabel?: ClassNameValue, linkLabelExternalIcon?: ClassNameValue, linkTrailing?: ClassNameValue, linkLeadingHint?: ClassNameValue, linkLeadingBadgeSize?: ClassNameValue, linkLeadingBadge?: ClassNameValue, linkTrailingIcon?: ClassNameValue, label?: ClassNameValue, link?: ClassNameValue, content?: ClassNameValue, childList?: ClassNameValue, childLabel?: ClassNameValue, childItem?: ClassNameValue, childLink?: ClassNameValue, childLinkIcon?: ClassNameValue, childLinkHint?: ClassNameValue, childLinkBadgeSize?: ClassNameValue, childLinkBadge?: ClassNameValue, childLinkWrapper?: ClassNameValue, childLinkLabel?: ClassNameValue, childLinkLabelExternalIcon?: ClassNameValue, popoverWrapper?: ClassNameValue }
You can pass any property from the Link component such as to, target, etc.
{
"wait": "Loading client-side content..."
}items prop to display groups of items.children array of objects to define submenus:label: stringicon?: IconComponentonSelect?(e: Event): voidclass?: any
Orientation
Use the orientation prop to change the orientation of the NavigationMenu.
vertical, an Accordion component is used to display each group. You can control the open state of each item using the open and defaultOpen properties and change the behavior using the collapsible and type props.viewportRtl set to ensure the drop-down menu is positioned correctly.{
"wait": "Loading client-side content..."
}horizontal and separated when orientation is vertical.Collapsed
In vertical orientation, use the collapsed prop to collapse the NavigationMenu, this can be useful in a sidebar for example.
Trailing Icon
Use the trailing-icon prop to customize the trailing Icon of each item. This icon is only displayed when an item has children.
trailingIcon property in the item object.{
"wait": "Loading client-side content..."
}Unmount
Use the unmount-on-hide prop to control the content unmounting behavior. Defaults to true.
{
"wait": "Loading client-side content..."
}Examples
With tooltip in items
When orientation is vertical and the menu is collapsed, you can set the tooltip prop to true to display a Tooltip around items with their label but you can also use the tooltip property on each item to override the default tooltip.
You can pass any property from the Tooltip component globally or on each item.
With popover in items
When orientation is vertical and the menu is collapsed, you can set the popover prop to true to display a Popover around items with their children but you can also use the popover property on each item to override the default popover.
You can pass any property from the Popover component globally or on each item.
Control active item
You can control the active item(s) by using the default-value prop or the v-model directive with the value of the item. If no value is provided, it defaults to item-${index} for top-level items or item-${level}-${index} for nested items.
defineShortcuts, you can switch the active item by pressing 1, 2, or 3.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.slot }}-content
#item, #item-leading, #item-label, #item-trailing and #item-content slots to customize all items.With content slot
Use the #item-content slot or the slot property (#{{ item.slot }}-content) to customize the content of a specific item.
sm:w-(--reka-navigation-menu-viewport-width) class on the viewport to have a dynamic width. This requires to set a width on the content's first child.API
Props
Slots
Emits
Theme
export default defineAppConfig({
b24ui: {
navigationMenu: {
slots: {
root: 'relative flex [&>div]:min-w-0 font-[family-name:var(--ui-font-family-secondary)]',
list: 'isolate min-w-0',
label: 'w-full h-[22px] overflow-hidden mt-[10px] opacity-70 text-(length:--ui-font-size-sm)',
item: 'min-w-0',
link: 'min-w-[38px] w-full max-w-full p-0 m-0 group relative cursor-pointer flex items-center gap-[2px] font-(--ui-font-weight-normal) text-(length:--ui-font-size-lg) focus:outline-none focus-visible:rounded-(--menu-item-border-radius) focus-visible:outline-none focus-visible:ring-inset focus-visible:ring-1 focus-visible:ring-(--ui-color-base-4) rounded-(--menu-item-border-radius) text-(--menu-item-color) bg-(--menu-item-background) hover:bg-(--menu-item-background-hover) data-[state=open]:bg-(--menu-item-background-hover) border-0',
linkLeadingIcon: 'shrink-0 size-[26px]',
linkLeadingAvatar: 'shrink-0',
linkLeadingAvatarSize: 'xs',
linkLeadingHint: 'inline-flex m-0 absolute -top-[5px] left-[8px] text-(length:--ui-font-size-4xs) leading-[8px] font-semibold text-(--b24ui-typography-description-color) uppercase ml-px',
linkLeadingBadge: 'inline-flex m-0 absolute',
linkLeadingBadgeSize: 'xs',
linkTrailing: 'group inline-flex mt-[2px] items-center',
linkTrailingIcon: 'text-(--ui-color-design-plain-na-content-icon) shrink-0',
linkLabel: 'truncate',
linkLabelWrapper: 'flex items-center justify-between rtl:flex-row-reverse',
linkLabelExternalIcon: 'inline-block size-[16px] text-(--ui-color-design-plain-content-icon-secondary)',
childList: 'isolate',
childLabel: '',
childItem: 'h-[36px] mt-(--menu-item-block-stack-space)',
childLink: 'group relative size-full flex flex-row rtl:flex-row-reverse items-center transition-colors text-start',
childLinkWrapper: 'min-w-0 flex-1 flex flex-row items-center justify-start rtl:justify-end gap-0.5',
childLinkIcon: 'size-[18px] shrink-0',
childLinkHint: 'inline-flex m-0 absolute -top-[2px] left-[24px] text-(length:--ui-font-size-4xs) leading-[8px] font-semibold text-(--b24ui-typography-description-color) uppercase ml-px',
childLinkBadge: 'inline-flex m-0',
childLinkBadgeSize: 'xs',
childLinkLabel: 'truncate ms-[2px] -mt-px',
childLinkLabelExternalIcon: 'inline-block size-4 text-(--ui-color-design-plain-content-icon-secondary)',
separator: 'h-px bg-(--leftmenu-bg-divider) my-[16px]',
popoverWrapper: 'px-0 py-(--menu-popup-padding)',
viewportWrapper: 'absolute top-[53px] left-0 flex w-full',
viewport: 'light relative overflow-hidden w-full bg-(--popup-window-background-color) shadow-(--popup-window-box-shadow) h-(--reka-navigation-menu-viewport-height) w-(--reka-navigation-menu-viewport-width) left-(--reka-navigation-menu-viewport-left) rounded-(--popup-window-border-radius) will-change-[opacity] [&:has(>[data-viewport=rtl])]:left-auto [&:has(>[data-viewport=rtl])]:-right-[calc(100%-var(--reka-navigation-menu-viewport-width))] transition-[width,height] duration-200 origin-[top_center] z-[1]',
content: ''
},
variants: {
orientation: {
horizontal: {
root: 'relative h-full items-center justify-between',
list: 'flex items-center gap-x-1 h-full',
item: 'empty:hidden',
link: 'menu-item-horizontal h-[32px] min-h-[32px] px-[10px] border border-(--menu-item-background) hover:border-(--ui-color-design-plain-na-focused-stroke) data-[state=open]:bg-(--ui-color-design-plain-na-focused-stroke)',
linkTrailingIcon: 'size-[16px]',
linkLeadingBadge: '-top-[6px] -right-[14px] -translate-x-1/2',
linkLabelWrapper: 'gap-[4px] truncate',
childList: 'grid px-0 py-(--menu-popup-padding)',
childLink: 'px-[18px] min-w-[195px] whitespace-nowrap font-[family-name:var(--ui-font-family-primary)] text-(length:--menu-popup-item-font-size) text-(--menu-popup-item-color) hover:text-(--menu-popup-item-color-hover) hover:bg-(--menu-popup-item-bg-color-hover)',
childLinkLabel: '',
content: 'absolute top-0 left-0 w-full max-h-[70vh] overflow-y-auto scrollbar-thin scrollbar-transparent'
},
vertical: {
root: 'flex-col w-full ps-(--menu-items-block-padding-x) rtl:pe-(--menu-items-block-padding-x)',
list: 'flex flex-col',
item: 'mt-(--menu-item-block-stack-space) data-[state=open]:rounded-(--menu-item-border-radius) data-[state=open]:border-(length:--leftmenu-group-stroke-weight) data-[state=open]:border-(--leftmenu-group-stroke)',
link: 'menu-item-vertical overflow-hidden h-[38px] min-h-[38px] p-[6px] flex-row rtl:flex-row-reverse justify-between data-[state=open]:text-(length:--ui-font-size-sm) data-[state=open]:opacity-70',
linkLeadingIcon: '',
linkTrailingIcon: 'size-[20px] group-data-[state=open]:rotate-180 transition-transform duration-200',
linkLeadingBadge: '-top-[4px] left-[24px] -translate-x-1/2',
linkLabelWrapper: 'relative h-[22px]',
childList: '',
childLink: 'px-[18px] min-w-[195px] whitespace-nowrap font-[family-name:var(--ui-font-family-primary)] text-(length:--menu-popup-item-font-size) text-(--menu-popup-item-color) hover:text-(--menu-popup-item-color-hover) hover:bg-(--menu-popup-item-bg-color-hover)',
childLabel: 'w-full min-w-[195px] 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:--popup-window-delimiter-font-size) text-(--popup-window-delimiter-text-color) font-(--popup-window-delimiter-font-weight) after:ms-[10px] after:block after:flex-1 after:min-w-[15px] after:h-px after:bg-(--popup-window-delimiter-bg-color)'
}
},
active: {
true: {
childLink: 'text-(--ui-color-accent-main-primary) hover:text-(--ui-color-accent-main-primary)',
childLinkIcon: 'text-(--ui-color-accent-main-primary)'
},
false: {
linkLeadingIcon: 'text-(--ui-color-design-plain-content-icon-secondary)',
childLinkIcon: 'text-(--ui-color-design-plain-content-icon-secondary) group-hover:text-(--ui-color-accent-main-primary)'
}
},
disabled: {
true: {
link: 'cursor-not-allowed opacity-75'
}
},
level: {
true: ''
},
collapsed: {
true: ''
}
},
compoundVariants: [
{
orientation: 'horizontal',
class: {
childList: '',
content: 'w-[240px]'
}
},
{
orientation: 'vertical',
collapsed: false,
class: {
item: 'data-[state=open]:bg-(--leftmenu-group-bg)',
childList: '',
childItem: '',
content: 'motion-safe:data-[state=open]:animate-[collapsible-down_200ms_ease-out] motion-safe:data-[state=closed]:animate-[collapsible-up_200ms_ease-out] overflow-hidden',
linkLabel: 'ms-[9px]'
}
},
{
orientation: 'vertical',
collapsed: true,
class: {
childList: 'grid px-0 py-(--menu-popup-padding)',
linkLabel: 'hidden',
linkTrailing: 'hidden'
}
},
{
orientation: 'vertical',
collapsed: false,
class: {
link: 'collapsed data-[state=open]:-mt-(--leftmenu-group-stroke-weight) data-[state=open]:-mx-(--leftmenu-group-stroke-weight)'
}
},
{
disabled: false,
active: false,
class: {
link: 'transition-colors',
linkLeadingIcon: 'group-hover:text-(--ui-color-design-selection-content-icon)'
}
},
{
active: true,
class: {
link: 'leading-9 text-(--menu-item-color-active) bg-(--menu-item-background-active)'
}
},
{
active: true,
orientation: 'horizontal',
class: {
link: 'menu-item-horizontal-active border-(--menu-item-border)'
}
},
{
active: true,
orientation: 'vertical',
class: {
link: 'menu-item-vertical-active'
}
}
],
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: {
navigationMenu: {
slots: {
root: 'relative flex [&>div]:min-w-0 font-[family-name:var(--ui-font-family-secondary)]',
list: 'isolate min-w-0',
label: 'w-full h-[22px] overflow-hidden mt-[10px] opacity-70 text-(length:--ui-font-size-sm)',
item: 'min-w-0',
link: 'min-w-[38px] w-full max-w-full p-0 m-0 group relative cursor-pointer flex items-center gap-[2px] font-(--ui-font-weight-normal) text-(length:--ui-font-size-lg) focus:outline-none focus-visible:rounded-(--menu-item-border-radius) focus-visible:outline-none focus-visible:ring-inset focus-visible:ring-1 focus-visible:ring-(--ui-color-base-4) rounded-(--menu-item-border-radius) text-(--menu-item-color) bg-(--menu-item-background) hover:bg-(--menu-item-background-hover) data-[state=open]:bg-(--menu-item-background-hover) border-0',
linkLeadingIcon: 'shrink-0 size-[26px]',
linkLeadingAvatar: 'shrink-0',
linkLeadingAvatarSize: 'xs',
linkLeadingHint: 'inline-flex m-0 absolute -top-[5px] left-[8px] text-(length:--ui-font-size-4xs) leading-[8px] font-semibold text-(--b24ui-typography-description-color) uppercase ml-px',
linkLeadingBadge: 'inline-flex m-0 absolute',
linkLeadingBadgeSize: 'xs',
linkTrailing: 'group inline-flex mt-[2px] items-center',
linkTrailingIcon: 'text-(--ui-color-design-plain-na-content-icon) shrink-0',
linkLabel: 'truncate',
linkLabelWrapper: 'flex items-center justify-between rtl:flex-row-reverse',
linkLabelExternalIcon: 'inline-block size-[16px] text-(--ui-color-design-plain-content-icon-secondary)',
childList: 'isolate',
childLabel: '',
childItem: 'h-[36px] mt-(--menu-item-block-stack-space)',
childLink: 'group relative size-full flex flex-row rtl:flex-row-reverse items-center transition-colors text-start',
childLinkWrapper: 'min-w-0 flex-1 flex flex-row items-center justify-start rtl:justify-end gap-0.5',
childLinkIcon: 'size-[18px] shrink-0',
childLinkHint: 'inline-flex m-0 absolute -top-[2px] left-[24px] text-(length:--ui-font-size-4xs) leading-[8px] font-semibold text-(--b24ui-typography-description-color) uppercase ml-px',
childLinkBadge: 'inline-flex m-0',
childLinkBadgeSize: 'xs',
childLinkLabel: 'truncate ms-[2px] -mt-px',
childLinkLabelExternalIcon: 'inline-block size-4 text-(--ui-color-design-plain-content-icon-secondary)',
separator: 'h-px bg-(--leftmenu-bg-divider) my-[16px]',
popoverWrapper: 'px-0 py-(--menu-popup-padding)',
viewportWrapper: 'absolute top-[53px] left-0 flex w-full',
viewport: 'light relative overflow-hidden w-full bg-(--popup-window-background-color) shadow-(--popup-window-box-shadow) h-(--reka-navigation-menu-viewport-height) w-(--reka-navigation-menu-viewport-width) left-(--reka-navigation-menu-viewport-left) rounded-(--popup-window-border-radius) will-change-[opacity] [&:has(>[data-viewport=rtl])]:left-auto [&:has(>[data-viewport=rtl])]:-right-[calc(100%-var(--reka-navigation-menu-viewport-width))] transition-[width,height] duration-200 origin-[top_center] z-[1]',
content: ''
},
variants: {
orientation: {
horizontal: {
root: 'relative h-full items-center justify-between',
list: 'flex items-center gap-x-1 h-full',
item: 'empty:hidden',
link: 'menu-item-horizontal h-[32px] min-h-[32px] px-[10px] border border-(--menu-item-background) hover:border-(--ui-color-design-plain-na-focused-stroke) data-[state=open]:bg-(--ui-color-design-plain-na-focused-stroke)',
linkTrailingIcon: 'size-[16px]',
linkLeadingBadge: '-top-[6px] -right-[14px] -translate-x-1/2',
linkLabelWrapper: 'gap-[4px] truncate',
childList: 'grid px-0 py-(--menu-popup-padding)',
childLink: 'px-[18px] min-w-[195px] whitespace-nowrap font-[family-name:var(--ui-font-family-primary)] text-(length:--menu-popup-item-font-size) text-(--menu-popup-item-color) hover:text-(--menu-popup-item-color-hover) hover:bg-(--menu-popup-item-bg-color-hover)',
childLinkLabel: '',
content: 'absolute top-0 left-0 w-full max-h-[70vh] overflow-y-auto scrollbar-thin scrollbar-transparent'
},
vertical: {
root: 'flex-col w-full ps-(--menu-items-block-padding-x) rtl:pe-(--menu-items-block-padding-x)',
list: 'flex flex-col',
item: 'mt-(--menu-item-block-stack-space) data-[state=open]:rounded-(--menu-item-border-radius) data-[state=open]:border-(length:--leftmenu-group-stroke-weight) data-[state=open]:border-(--leftmenu-group-stroke)',
link: 'menu-item-vertical overflow-hidden h-[38px] min-h-[38px] p-[6px] flex-row rtl:flex-row-reverse justify-between data-[state=open]:text-(length:--ui-font-size-sm) data-[state=open]:opacity-70',
linkLeadingIcon: '',
linkTrailingIcon: 'size-[20px] group-data-[state=open]:rotate-180 transition-transform duration-200',
linkLeadingBadge: '-top-[4px] left-[24px] -translate-x-1/2',
linkLabelWrapper: 'relative h-[22px]',
childList: '',
childLink: 'px-[18px] min-w-[195px] whitespace-nowrap font-[family-name:var(--ui-font-family-primary)] text-(length:--menu-popup-item-font-size) text-(--menu-popup-item-color) hover:text-(--menu-popup-item-color-hover) hover:bg-(--menu-popup-item-bg-color-hover)',
childLabel: 'w-full min-w-[195px] 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:--popup-window-delimiter-font-size) text-(--popup-window-delimiter-text-color) font-(--popup-window-delimiter-font-weight) after:ms-[10px] after:block after:flex-1 after:min-w-[15px] after:h-px after:bg-(--popup-window-delimiter-bg-color)'
}
},
active: {
true: {
childLink: 'text-(--ui-color-accent-main-primary) hover:text-(--ui-color-accent-main-primary)',
childLinkIcon: 'text-(--ui-color-accent-main-primary)'
},
false: {
linkLeadingIcon: 'text-(--ui-color-design-plain-content-icon-secondary)',
childLinkIcon: 'text-(--ui-color-design-plain-content-icon-secondary) group-hover:text-(--ui-color-accent-main-primary)'
}
},
disabled: {
true: {
link: 'cursor-not-allowed opacity-75'
}
},
level: {
true: ''
},
collapsed: {
true: ''
}
},
compoundVariants: [
{
orientation: 'horizontal',
class: {
childList: '',
content: 'w-[240px]'
}
},
{
orientation: 'vertical',
collapsed: false,
class: {
item: 'data-[state=open]:bg-(--leftmenu-group-bg)',
childList: '',
childItem: '',
content: 'motion-safe:data-[state=open]:animate-[collapsible-down_200ms_ease-out] motion-safe:data-[state=closed]:animate-[collapsible-up_200ms_ease-out] overflow-hidden',
linkLabel: 'ms-[9px]'
}
},
{
orientation: 'vertical',
collapsed: true,
class: {
childList: 'grid px-0 py-(--menu-popup-padding)',
linkLabel: 'hidden',
linkTrailing: 'hidden'
}
},
{
orientation: 'vertical',
collapsed: false,
class: {
link: 'collapsed data-[state=open]:-mt-(--leftmenu-group-stroke-weight) data-[state=open]:-mx-(--leftmenu-group-stroke-weight)'
}
},
{
disabled: false,
active: false,
class: {
link: 'transition-colors',
linkLeadingIcon: 'group-hover:text-(--ui-color-design-selection-content-icon)'
}
},
{
active: true,
class: {
link: 'leading-9 text-(--menu-item-color-active) bg-(--menu-item-background-active)'
}
},
{
active: true,
orientation: 'horizontal',
class: {
link: 'menu-item-horizontal-active border-(--menu-item-border)'
}
},
{
active: true,
orientation: 'vertical',
class: {
link: 'menu-item-vertical-active'
}
}
],
defaultVariants: {}
}
}
})
]
})