Menubar

An app-style menubar whose menus fade and scale out of their trigger, with a highlight that glides between items.

Preview

Setup

Install with the shadcn CLI

$npx shadcn@latest add https://kinetikui.vercel.app/r/menubar.json

One command adds every file, the npm packages and any Kinetik components it builds on. Needs a components.json; the CLI offers to create one if your project has none.

Or install manually

  1. 1

    Run in your terminal:

    $npm install clsx tailwind-merge
  2. 2

    Copy lib/utils.ts from the Code tab. Skip if you already have cn().

  3. 3

    Copy styles/tokens.css from the Code tab and import it in your global CSS after Tailwind: @import "./styles/tokens.css";

  4. 4

    Create a components/ui/menubar/ folder and copy every file from the Code tab into it. Each file does one job, so you can read or change a piece without the rest.

  5. 5

    Import and render:

    Example
    import { Menubar } from "@/components/ui/menubar"
    
    <Menubar menus={[{ label: "File", items: [{ label: "New file" }] }]} />

Usage

Describe the menus as data. A light pill slides between the triggers as you hover; a menu fades and scales out of the trigger that opened it, and a soft highlight glides between its items. While a menu is open, hovering another trigger switches to it.

import { FilePlus, Save } from "lucide-react"
import { Menubar } from "@/components/ui/menubar"

export function EditorBar() {
  const [minimap, setMinimap] = useState(false)

  return (
    <Menubar
      label="Editor"
      menus={[
        {
          label: "File",
          items: [
            { type: "label", label: "Document" },
            { label: "New file", icon: <FilePlus />, shortcut: "Ctrl N", onSelect: createFile },
            { type: "submenu", label: "Open recent", items: recentFiles },
            { type: "separator" },
            { label: "Save", icon: <Save />, shortcut: "Ctrl S", onSelect: save },
          ],
        },
        {
          label: "View",
          items: [{ type: "checkbox", label: "Minimap", checked: minimap, onCheckedChange: setMinimap }],
        },
      ]}
    />
  )
}

Entries

typeFieldsNotes
(none) or "item"label, icon?, shortcut?, disabled?, onSelect?Selecting closes the menu. shortcut is display only.
"checkbox"label, checked, onCheckedChange, shortcut?Stays open when toggled.
"submenu"label, icon?, itemsOpens to the side on hover, click or Right arrow.
"label"labelA small heading for a group.
"separator"—A thin rule between groups.

Props

PropTypeDefaultNotes
menus{ label; items: MenubarEntry[] }[]—One per trigger.
labelstring"Menu"Accessible name for the menubar.
classNamestring—Applied to the wrapper.

Accessibility

  • A menubar of triggers, each opening a menu of menuitem and menuitemcheckbox rows
  • One Tab stop on the bar: Left and Right move between triggers; Down, Enter or Space opens a menu
  • In a menu: Up and Down move, Home and End jump, Right opens a submenu, Left or Escape goes back
  • Closed menus are inert, so they fade out without being reachable by keyboard or screen readers
  • Clicking outside closes the menu; with reduced motion, everything changes instantly