Menubar wrappers
import { Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger } from '@/components/ui/menubar'
...import { Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger } from '@/components/ui/menubar'
export default function MenubarDemoExample() {
return (
<Menubar class="w-72"><MenubarMenu><MenubarTrigger>File</MenubarTrigger><MenubarContent><MenubarGroup><MenubarItem>New Tab <MenubarShortcut>⌘T</MenubarShortcut></MenubarItem><MenubarItem>New Window <MenubarShortcut>⌘N</MenubarShortcut></MenubarItem><MenubarItem disabled>New Incognito Window</MenubarItem></MenubarGroup><MenubarSeparator /><MenubarSub><MenubarSubTrigger>Share</MenubarSubTrigger><MenubarSubContent><MenubarItem>Email link</MenubarItem><MenubarItem>Messages</MenubarItem><MenubarItem>Notes</MenubarItem></MenubarSubContent></MenubarSub><MenubarSeparator /><MenubarItem>Print... <MenubarShortcut>⌘P</MenubarShortcut></MenubarItem></MenubarContent></MenubarMenu><MenubarMenu><MenubarTrigger>Edit</MenubarTrigger><MenubarContent><MenubarItem>Undo <MenubarShortcut>⌘Z</MenubarShortcut></MenubarItem><MenubarItem>Redo <MenubarShortcut>⇧⌘Z</MenubarShortcut></MenubarItem><MenubarSeparator /><MenubarSub><MenubarSubTrigger>Find</MenubarSubTrigger><MenubarSubContent><MenubarItem>Search the web</MenubarItem><MenubarSeparator /><MenubarItem>Find...</MenubarItem><MenubarItem>Find Next</MenubarItem><MenubarItem>Find Previous</MenubarItem></MenubarSubContent></MenubarSub><MenubarSeparator /><MenubarItem>Cut</MenubarItem><MenubarItem>Copy</MenubarItem><MenubarItem>Paste</MenubarItem></MenubarContent></MenubarMenu><MenubarMenu><MenubarTrigger>View</MenubarTrigger><MenubarContent class="w-44"><MenubarCheckboxItem>Bookmarks Bar</MenubarCheckboxItem><MenubarCheckboxItem checked>Full URLs</MenubarCheckboxItem><MenubarSeparator /><MenubarItem inset>Reload <MenubarShortcut>⌘R</MenubarShortcut></MenubarItem><MenubarItem disabled inset>Force Reload <MenubarShortcut>⇧⌘R</MenubarShortcut></MenubarItem><MenubarSeparator /><MenubarItem inset>Toggle Fullscreen</MenubarItem><MenubarSeparator /><MenubarItem inset>Hide Sidebar</MenubarItem></MenubarContent></MenubarMenu><MenubarMenu><MenubarTrigger>Profiles</MenubarTrigger><MenubarContent><MenubarRadioGroup value="benoit"><MenubarRadioItem value="andy">Andy</MenubarRadioItem><MenubarRadioItem value="benoit">Benoit</MenubarRadioItem><MenubarRadioItem value="luis">Luis</MenubarRadioItem></MenubarRadioGroup><MenubarSeparator /><MenubarItem inset>Edit...</MenubarItem><MenubarSeparator /><MenubarItem inset>Add Profile...</MenubarItem></MenubarContent></MenubarMenu></Menubar>
)
}
Installation
npx @fictjs/shadcn@latest add menubarInstall the runtime dependencies:
npm install @fictjs/radix-uiCopy the Fict shadcn component into your project.
Source
components/ui/menubar.tsx
src/components/ui/menubar.tsx
import { Menubar as MenubarPrimitive } from '@fictjs/radix-ui'
import { cn } from '@/lib/cn'
export const Menubar = MenubarPrimitive.Root
export const MenubarMenu = MenubarPrimitive.Menu
export const MenubarGroup = MenubarPrimitive.Group
export const MenubarRadioGroup = MenubarPrimitive.RadioGroup
export const MenubarSub = MenubarPrimitive.Sub
type GenericProps = {
class?: string
children?: unknown
[key: string]: unknown
}
export function MenubarTrigger(props: GenericProps) {
const { class: className, ...rest } = props
return (
<MenubarPrimitive.Trigger
class={cn('flex cursor-default select-none items-center rounded-sm px-3 py-1.5 text-sm font-medium outline-none hover:bg-accent hover:text-accent-foreground', className)}
{...rest}
/>
)
}
export function MenubarContent(props: GenericProps) {
const { class: className, ...rest } = props
return (
<MenubarPrimitive.Content
class={cn('z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md', className)}
{...rest}
/>
)
}
export function MenubarItem(props: GenericProps) {
const { class: className, inset, variant = 'default', ...rest } = props
return (
<MenubarPrimitive.Item
data-variant={variant}
class={cn('relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground', inset && 'pl-8', variant === 'destructive' && 'text-destructive focus:bg-destructive/10', className)}
{...rest}
/>
)
}
export function MenubarCheckboxItem(props: GenericProps) {
const { class: className, ...rest } = props
return <MenubarPrimitive.CheckboxItem class={cn('relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none hover:bg-accent', className)} {...rest} />
}
export function MenubarRadioItem(props: GenericProps) {
const { class: className, ...rest } = props
return <MenubarPrimitive.RadioItem class={cn('relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none hover:bg-accent', className)} {...rest} />
}
export function MenubarSeparator(props: GenericProps) {
const { class: className, ...rest } = props
return <MenubarPrimitive.Separator class={cn('-mx-1 my-1 h-px bg-muted', className)} {...rest} />
}
export function MenubarShortcut(props: GenericProps) {
const { class: className, ...rest } = props
return <span class={cn('ml-auto text-xs tracking-widest text-muted-foreground', className)} {...rest} />
}
export function MenubarSubTrigger(props: GenericProps) {
const { class: className, inset, ...rest } = props
return <MenubarPrimitive.SubTrigger class={cn('flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent data-[state=open]:bg-accent', inset && 'pl-8', className)} {...rest} />
}
export function MenubarSubContent(props: GenericProps) {
const { class: className, ...rest } = props
return <MenubarPrimitive.SubContent class={cn('z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg', className)} {...rest} />
}
Usage
Examples
Checkbox
import { Menubar, MenubarCheckboxItem, MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarShortcut, MenubarTrigger } from '@/components/ui/menubar'
...import { Menubar, MenubarCheckboxItem, MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarShortcut, MenubarTrigger } from '@/components/ui/menubar'
export default function MenubarCheckboxExample() {
return (
<Menubar class="w-72"><MenubarMenu><MenubarTrigger>View</MenubarTrigger><MenubarContent class="w-64"><MenubarCheckboxItem>Always Show Bookmarks Bar</MenubarCheckboxItem><MenubarCheckboxItem checked>Always Show Full URLs</MenubarCheckboxItem><MenubarSeparator /><MenubarItem inset>Reload <MenubarShortcut>⌘R</MenubarShortcut></MenubarItem><MenubarItem disabled inset>Force Reload <MenubarShortcut>⇧⌘R</MenubarShortcut></MenubarItem></MenubarContent></MenubarMenu><MenubarMenu><MenubarTrigger>Format</MenubarTrigger><MenubarContent><MenubarCheckboxItem checked>Strikethrough</MenubarCheckboxItem><MenubarCheckboxItem>Code</MenubarCheckboxItem><MenubarCheckboxItem>Superscript</MenubarCheckboxItem></MenubarContent></MenubarMenu></Menubar>
)
}
Radio
import { Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarTrigger } from '@/components/ui/menubar'
...import { Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarTrigger } from '@/components/ui/menubar'
export default function MenubarRadioExample() {
let user = $state('benoit')
let theme = $state('system')
return (
<Menubar class="w-72"><MenubarMenu><MenubarTrigger>Profiles</MenubarTrigger><MenubarContent><MenubarRadioGroup value={() => user} onValueChange={value => user = value}><MenubarRadioItem value="andy">Andy</MenubarRadioItem><MenubarRadioItem value="benoit">Benoit</MenubarRadioItem><MenubarRadioItem value="luis">Luis</MenubarRadioItem></MenubarRadioGroup><MenubarSeparator /><MenubarItem inset>Edit...</MenubarItem><MenubarItem inset>Add Profile...</MenubarItem></MenubarContent></MenubarMenu><MenubarMenu><MenubarTrigger>Theme</MenubarTrigger><MenubarContent><MenubarRadioGroup value={() => theme} onValueChange={value => theme = value}><MenubarRadioItem value="light">Light</MenubarRadioItem><MenubarRadioItem value="dark">Dark</MenubarRadioItem><MenubarRadioItem value="system">System</MenubarRadioItem></MenubarRadioGroup></MenubarContent></MenubarMenu></Menubar>
)
}
Submenu
import { Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger } from '@/components/ui/menubar'
...import { Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger } from '@/components/ui/menubar'
export default function MenubarSubmenuExample() {
return (
<Menubar class="w-72"><MenubarMenu><MenubarTrigger>File</MenubarTrigger><MenubarContent><MenubarSub><MenubarSubTrigger>Share</MenubarSubTrigger><MenubarSubContent><MenubarItem>Email link</MenubarItem><MenubarItem>Messages</MenubarItem><MenubarItem>Notes</MenubarItem></MenubarSubContent></MenubarSub><MenubarSeparator /><MenubarItem>Print... <MenubarShortcut>⌘P</MenubarShortcut></MenubarItem></MenubarContent></MenubarMenu><MenubarMenu><MenubarTrigger>Edit</MenubarTrigger><MenubarContent><MenubarItem>Undo <MenubarShortcut>⌘Z</MenubarShortcut></MenubarItem><MenubarItem>Redo <MenubarShortcut>⇧⌘Z</MenubarShortcut></MenubarItem><MenubarSeparator /><MenubarSub><MenubarSubTrigger>Find</MenubarSubTrigger><MenubarSubContent><MenubarItem>Find...</MenubarItem><MenubarItem>Find Next</MenubarItem><MenubarItem>Find Previous</MenubarItem></MenubarSubContent></MenubarSub><MenubarSeparator /><MenubarItem>Cut</MenubarItem><MenubarItem>Copy</MenubarItem><MenubarItem>Paste</MenubarItem></MenubarContent></MenubarMenu></Menubar>
)
}
Icons
import { Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarShortcut, MenubarTrigger } from '@/components/ui/menubar'
...import { Menubar, MenubarContent, MenubarItem, MenubarMenu, MenubarSeparator, MenubarShortcut, MenubarTrigger } from '@/components/ui/menubar'
function Icon(props: { name: string }) {
return <svg aria-label={props.name} viewBox="0 0 24 24"><path d="M4 4h16v16H4zM8 9h8M8 13h6" /></svg>
}
export default function MenubarIconsExample() {
return (
<Menubar class="w-72"><MenubarMenu><MenubarTrigger>File</MenubarTrigger><MenubarContent><MenubarItem><Icon name="File" />New File <MenubarShortcut>⌘N</MenubarShortcut></MenubarItem><MenubarItem><Icon name="Folder" />Open Folder</MenubarItem><MenubarSeparator /><MenubarItem><Icon name="Save" />Save <MenubarShortcut>⌘S</MenubarShortcut></MenubarItem></MenubarContent></MenubarMenu><MenubarMenu><MenubarTrigger>More</MenubarTrigger><MenubarContent><MenubarItem><Icon name="Settings" />Settings</MenubarItem><MenubarItem><Icon name="Help" />Help</MenubarItem><MenubarSeparator /><MenubarItem variant="destructive"><Icon name="Trash" />Delete</MenubarItem></MenubarContent></MenubarMenu></Menubar>
)
}
Rtl
import { Menubar, MenubarCheckboxItem, MenubarContent, MenubarItem, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger } from '@/components/ui/menubar'
...import { Menubar, MenubarCheckboxItem, MenubarContent, MenubarItem, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger } from '@/components/ui/menubar'
const translations = {
ar: { dir: 'rtl', file: 'ملف', edit: 'تعديل', view: 'عرض', profiles: 'الملفات الشخصية', newTab: 'علامة تبويب جديدة', newWindow: 'نافذة جديدة', incognito: 'نافذة التصفح المتخفي الجديدة', share: 'مشاركة', email: 'رابط البريد الإلكتروني', messages: 'الرسائل', notes: 'الملاحظات', print: 'طباعة...', undo: 'تراجع', redo: 'إعادة', find: 'بحث', searchWeb: 'البحث على الويب', findItem: 'بحث...', findNext: 'البحث التالي', findPrevious: 'البحث السابق', cut: 'قص', copy: 'نسخ', paste: 'لصق', bookmarks: 'شريط الإشارات المرجعية', urls: 'عناوين URL الكاملة', reload: 'إعادة تحميل', forceReload: 'إعادة تحميل قسري', fullscreen: 'تبديل وضع ملء الشاشة', sidebar: 'إخفاء الشريط الجانبي', editProfile: 'تعديل...', addProfile: 'إضافة ملف شخصي...' },
he: { dir: 'rtl', file: 'קובץ', edit: 'ערוך', view: 'תצוגה', profiles: 'פרופילים', newTab: 'כרטיסייה חדשה', newWindow: 'חלון חדש', incognito: 'חלון גלישה בסתר חדש', share: 'שתף', email: 'קישור אימייל', messages: 'הודעות', notes: 'הערות', print: 'הדפס...', undo: 'בטל', redo: 'בצע שוב', find: 'מצא', searchWeb: 'חפש באינטרנט', findItem: 'מצא...', findNext: 'מצא הבא', findPrevious: 'מצא הקודם', cut: 'גזור', copy: 'העתק', paste: 'הדבק', bookmarks: 'סרגל סימניות', urls: 'כתובות URL מלאות', reload: 'רענן', forceReload: 'רענן בכוח', fullscreen: 'החלף מסך מלא', sidebar: 'הסתר סרגל צד', editProfile: 'ערוך...', addProfile: 'הוסף פרופיל...' },
en: { dir: 'ltr', file: 'File', edit: 'Edit', view: 'View', profiles: 'Profiles', newTab: 'New Tab', newWindow: 'New Window', incognito: 'New Incognito Window', share: 'Share', email: 'Email link', messages: 'Messages', notes: 'Notes', print: 'Print...', undo: 'Undo', redo: 'Redo', find: 'Find', searchWeb: 'Search the web', findItem: 'Find...', findNext: 'Find Next', findPrevious: 'Find Previous', cut: 'Cut', copy: 'Copy', paste: 'Paste', bookmarks: 'Bookmarks Bar', urls: 'Full URLs', reload: 'Reload', forceReload: 'Force Reload', fullscreen: 'Toggle Fullscreen', sidebar: 'Hide Sidebar', editProfile: 'Edit...', addProfile: 'Add Profile...' },
} as const
export default function MenubarRtlExample() {
let language = $state<keyof typeof translations>('ar')
const t = translations[language]
return (
<div><select aria-label="Preview language" value={language} onChange={event => language = event.currentTarget.value as keyof typeof translations}><option value="ar">Arabic (العربية)</option><option value="he">Hebrew (עברית)</option><option value="en">English</option></select><Menubar class="w-72" dir={t.dir}><MenubarMenu><MenubarTrigger>{t.file}</MenubarTrigger><MenubarContent dir={t.dir}><MenubarItem>{t.newTab} <MenubarShortcut>⌘T</MenubarShortcut></MenubarItem><MenubarItem>{t.newWindow} <MenubarShortcut>⌘N</MenubarShortcut></MenubarItem><MenubarItem disabled>{t.incognito}</MenubarItem><MenubarSeparator /><MenubarSub><MenubarSubTrigger>{t.share}</MenubarSubTrigger><MenubarSubContent dir={t.dir}><MenubarItem>{t.email}</MenubarItem><MenubarItem>{t.messages}</MenubarItem><MenubarItem>{t.notes}</MenubarItem></MenubarSubContent></MenubarSub><MenubarSeparator /><MenubarItem>{t.print} <MenubarShortcut>⌘P</MenubarShortcut></MenubarItem></MenubarContent></MenubarMenu><MenubarMenu><MenubarTrigger>{t.edit}</MenubarTrigger><MenubarContent dir={t.dir}><MenubarItem>{t.undo} <MenubarShortcut>⌘Z</MenubarShortcut></MenubarItem><MenubarItem>{t.redo} <MenubarShortcut>⇧⌘Z</MenubarShortcut></MenubarItem><MenubarSeparator /><MenubarSub><MenubarSubTrigger>{t.find}</MenubarSubTrigger><MenubarSubContent dir={t.dir}><MenubarItem>{t.searchWeb}</MenubarItem><MenubarSeparator /><MenubarItem>{t.findItem}</MenubarItem><MenubarItem>{t.findNext}</MenubarItem><MenubarItem>{t.findPrevious}</MenubarItem></MenubarSubContent></MenubarSub><MenubarSeparator /><MenubarItem>{t.cut}</MenubarItem><MenubarItem>{t.copy}</MenubarItem><MenubarItem>{t.paste}</MenubarItem></MenubarContent></MenubarMenu><MenubarMenu><MenubarTrigger>{t.view}</MenubarTrigger><MenubarContent class="w-44" dir={t.dir}><MenubarCheckboxItem>{t.bookmarks}</MenubarCheckboxItem><MenubarCheckboxItem checked>{t.urls}</MenubarCheckboxItem><MenubarSeparator /><MenubarItem inset>{t.reload} <MenubarShortcut>⌘R</MenubarShortcut></MenubarItem><MenubarItem disabled inset>{t.forceReload} <MenubarShortcut>⇧⌘R</MenubarShortcut></MenubarItem><MenubarSeparator /><MenubarItem inset>{t.fullscreen}</MenubarItem><MenubarSeparator /><MenubarItem inset>{t.sidebar}</MenubarItem></MenubarContent></MenubarMenu><MenubarMenu><MenubarTrigger>{t.profiles}</MenubarTrigger><MenubarContent dir={t.dir}><MenubarRadioGroup value="benoit"><MenubarRadioItem value="andy">Andy</MenubarRadioItem><MenubarRadioItem value="benoit">Benoit</MenubarRadioItem><MenubarRadioItem value="luis">Luis</MenubarRadioItem></MenubarRadioGroup><MenubarSeparator /><MenubarItem inset>{t.editProfile}</MenubarItem><MenubarSeparator /><MenubarItem inset>{t.addProfile}</MenubarItem></MenubarContent></MenubarMenu></Menubar></div>
)
}