Menu

Context or dropdown menu with nested submenus.

import { Menu } from 'ui-lab-components/menu';
Offset (pop-over)4
"use client";
 
import { Menu } from 'ui-lab-components/menu';
 
export default function Example() {
  return (
    <Menu>
      <Menu.Trigger as="child">
        <div className="flex w-64 cursor-context-menu select-none items-center justify-center rounded-md border-2 border-dashed border-background-600 p-12 text-foreground-300 transition-colors hover:border-background-500">
          Right click here
        </div>
      </Menu.Trigger>
      <Menu.Content>
        <Menu.Item onSelect={() => {}}>
          Copy
          <Menu.Shortcut>⌘C</Menu.Shortcut>
        </Menu.Item>
        <Menu.Item onSelect={() => {}}>
          Paste
          <Menu.Shortcut>⌘V</Menu.Shortcut>
        </Menu.Item>
        <Menu.Separator />
        <Menu.Item disabled onSelect={() => {}}>
          Cut
          <Menu.Shortcut>⌘X</Menu.Shortcut>
        </Menu.Item>
      </Menu.Content>
    </Menu>
  );
}
 

menu/02-nested

Context menu with submenus for organizing related actions. Hover over items with arrows to reveal nested options.

Loading interactive preview
import { Menu } from 'ui-lab-components/menu';
 
export default function Example() {
  return (
    <Menu>
      <Menu.Trigger className="flex items-center justify-center rounded-md border-2 border-dashed border-background-600 p-12 w-full cursor-context-menu select-none text-foreground-300 hover:border-background-500 transition-colors">
        Right click here
      </Menu.Trigger>
      <Menu.Content>
        <Menu.Item>New File</Menu.Item>
        <Menu.Item>New Folder</Menu.Item>
        <Menu.Separator />
        <Menu.Sub>
          <Menu.SubTrigger>Open with...</Menu.SubTrigger>
          <Menu.SubContent>
            <Menu.Item>VS Code</Menu.Item>
            <Menu.Item>Sublime Text</Menu.Item>
            <Menu.Item>Vim</Menu.Item>
            <Menu.Separator />
            <Menu.Item>Other Application...</Menu.Item>
          </Menu.SubContent>
        </Menu.Sub>
        <Menu.Sub>
          <Menu.SubTrigger>Share</Menu.SubTrigger>
          <Menu.SubContent>
            <Menu.Item>Copy Link</Menu.Item>
            <Menu.Item>Email</Menu.Item>
            <Menu.Sub>
              <Menu.SubTrigger>Social Media</Menu.SubTrigger>
              <Menu.SubContent>
                <Menu.Item>Twitter</Menu.Item>
                <Menu.Item>LinkedIn</Menu.Item>
                <Menu.Item>Facebook</Menu.Item>
              </Menu.SubContent>
            </Menu.Sub>
          </Menu.SubContent>
        </Menu.Sub>
        <Menu.Separator />
        <Menu.Item>Rename</Menu.Item>
        <Menu.Item disabled>Delete</Menu.Item>
      </Menu.Content>
    </Menu>
  );
}
 

menu/03-toolbar-dropdown

Dropdown menu of actions with keyboard shortcuts and a disabled item.

Loading interactive preview
import { Menu } from 'ui-lab-components/menu'
import { Icon } from "ui-lab-components/icon"
 
export default function Example() {
  return (
    <Menu type="pop-over">
      <Menu.Trigger variant="ghost">
        File <Icon id="chev" size={12} className="ml-1" />
      </Menu.Trigger>
      <Menu.Content align="start">
        <Menu.Item onSelect={() => {}}>
          New file
          <Menu.Shortcut>⌘N</Menu.Shortcut>
        </Menu.Item>
        <Menu.Item onSelect={() => {}}>
          Open…
          <Menu.Shortcut>⌘O</Menu.Shortcut>
        </Menu.Item>
        <Menu.Item onSelect={() => {}}>
          Save
          <Menu.Shortcut>⌘S</Menu.Shortcut>
        </Menu.Item>
        <Menu.Separator />
        <Menu.Item disabled>Recent files</Menu.Item>
      </Menu.Content>
    </Menu>
  );
}
 

menu/04-table-row-actions

Per-row overflow menu in a table, with a destructive action separated from neutral ones.

Loading interactive preview
import { Menu } from 'ui-lab-components/menu'
import { Icon } from "ui-lab-components/icon"
 
const rows = [
  { id: "doc_1", name: "Q3 roadmap", updated: "2 hours ago" },
  { id: "doc_2", name: "Pricing review", updated: "yesterday" },
  { id: "doc_3", name: "Hiring plan", updated: "3 days ago" },
];
 
export default function Example() {
  return (
    <table className="w-full text-sm border-collapse">
      <thead>
        <tr className="border-b border-background-700">
          <th className="text-left py-2 px-3 font-medium text-foreground-200">Document</th>
          <th className="text-left py-2 px-3 font-medium text-foreground-200">Updated</th>
          <th className="py-2 px-3" />
        </tr>
      </thead>
      <tbody>
        {rows.map((row) => (
          <tr key={row.id} className="border-b border-background-700 last:border-0">
            <td className="py-2 px-3 text-foreground-100">{row.name}</td>
            <td className="py-2 px-3 text-foreground-400">{row.updated}</td>
            <td className="py-2 px-3 text-right">
              <Menu type="pop-over">
                <Menu.Trigger icon={<Icon id="more" size="1em" />} size="icon" variant="ghost" aria-label={`Row actions for ${row.name}`} />
                <Menu.Content align="end">
                  <Menu.Item onSelect={() => { }}>Open</Menu.Item>
                  <Menu.Item onSelect={() => { }}>Rename</Menu.Item>
                  <Menu.Item onSelect={() => { }}>Duplicate</Menu.Item>
                  <Menu.Separator />
                  <Menu.Item onSelect={() => { }} styles={{ root: "text-destructive" }}>
                    Delete
                  </Menu.Item>
                </Menu.Content>
              </Menu>
            </td>
          </tr>
        ))}
      </tbody>
    </table>
  );
}
 

menu/05-context-menu

Right-click anywhere in the surface to open the menu at the cursor position.

Loading interactive preview
import { Menu } from 'ui-lab-components/menu';
 
export default function Example() {
  return (
    <Menu type="context-menu">
      <Menu.Trigger as="child">
        <div className="flex items-center justify-center h-32 border border-dashed border-background-700 rounded-sm text-sm text-foreground-400 select-none">
          Right-click anywhere in this area
        </div>
      </Menu.Trigger>
      <Menu.Content>
        <Menu.Item onSelect={() => {}}>
          Cut
          <Menu.Shortcut>⌘X</Menu.Shortcut>
        </Menu.Item>
        <Menu.Item onSelect={() => {}}>
          Copy
          <Menu.Shortcut>⌘C</Menu.Shortcut>
        </Menu.Item>
        <Menu.Item onSelect={() => {}}>
          Paste
          <Menu.Shortcut>⌘V</Menu.Shortcut>
        </Menu.Item>
        <Menu.Separator />
        <Menu.Item onSelect={() => {}} styles={{ root: "text-destructive" }}>
          Delete
        </Menu.Item>
      </Menu.Content>
    </Menu>
  );
}
 

menu/06-view-options

Mixed checkbox and radio items for toggling display state and selecting a single density.

Loading interactive preview
"use client";
 
import { useState } from "react";
import { Menu } from 'ui-lab-components/menu'
 
export default function Example() {
  const [showGrid, setShowGrid] = useState(true);
  const [showRulers, setShowRulers] = useState(false);
  const [density, setDensity] = useState("comfortable");
 
  return (
    <Menu type="pop-over">
      <Menu.Trigger>View</Menu.Trigger>
      <Menu.Content align="start">
        <Menu.Label>Display</Menu.Label>
        <Menu.CheckboxItem checked={showGrid} onCheckedChange={setShowGrid}>
          Show grid
        </Menu.CheckboxItem>
        <Menu.CheckboxItem checked={showRulers} onCheckedChange={setShowRulers}>
          Show rulers
        </Menu.CheckboxItem>
        <Menu.Separator />
        <Menu.Label>Density</Menu.Label>
        <Menu.RadioGroup value={density} onValueChange={setDensity}>
          <Menu.RadioItem value="compact">Compact</Menu.RadioItem>
          <Menu.RadioItem value="comfortable">Comfortable</Menu.RadioItem>
          <Menu.RadioItem value="spacious">Spacious</Menu.RadioItem>
        </Menu.RadioGroup>
      </Menu.Content>
    </Menu>
  );
}
 

menu/07-submenus

A pop-over menu with flyout submenus for grouping actions, including a second level of nested options.

Loading interactive preview
import { Menu } from 'ui-lab-components/menu';
 
export default function Example() {
  return (
    <Menu type="pop-over">
      <Menu.Trigger>Open menu</Menu.Trigger>
      <Menu.Content align="start">
        <Menu.Item>New document</Menu.Item>
        <Menu.Item>Open document</Menu.Item>
        <Menu.Separator />
        <Menu.Sub>
          <Menu.SubTrigger>Open recent</Menu.SubTrigger>
          <Menu.SubContent>
            <Menu.Item>Project proposal</Menu.Item>
            <Menu.Item>Quarterly report</Menu.Item>
            <Menu.Item>Meeting notes</Menu.Item>
            <Menu.Separator />
            <Menu.Item>Clear recent documents</Menu.Item>
          </Menu.SubContent>
        </Menu.Sub>
        <Menu.Sub>
          <Menu.SubTrigger>Share</Menu.SubTrigger>
          <Menu.SubContent>
            <Menu.Item>Copy link</Menu.Item>
            <Menu.Item>Email a copy</Menu.Item>
            <Menu.Sub>
              <Menu.SubTrigger>Permissions</Menu.SubTrigger>
              <Menu.SubContent>
                <Menu.Item>Can view</Menu.Item>
                <Menu.Item>Can comment</Menu.Item>
                <Menu.Item>Can edit</Menu.Item>
              </Menu.SubContent>
            </Menu.Sub>
          </Menu.SubContent>
        </Menu.Sub>
        <Menu.Separator />
        <Menu.Item>Close document</Menu.Item>
      </Menu.Content>
    </Menu>
  );
}