For AI agents: the complete documentation index is available at https://ifhover.github.io/leaf-ui/v/0.6.0/en/llms.txt, the full documentation bundle is available at https://ifhover.github.io/leaf-ui/v/0.6.0/en/llms-full.txt, and this page is available as Markdown at https://ifhover.github.io/leaf-ui/v/0.6.0/en/components/menu.md.
  • English
  • Menu

    Organize hierarchical navigation.

    Basic usage

    basic.tsx
    import { Menu } from '@ifhover/leaf-ui';
    
    import { FolderKanban, House, Palette, Rocket, Settings, Users } from 'lucide-react';
    
    export function MenuBasic() {
      return (
        <Menu
          mode="inline"
          defaultSelectedKey="design"
          defaultOpenKeys={['projects']}
          items={[
            { key: 'home', label: 'Overview', icon: <House /> },
            {
              key: 'projects',
              label: 'Projects',
              icon: <FolderKanban />,
              children: [
                { key: 'design', label: 'Design resources', icon: <Palette /> },
                { key: 'release', label: 'Releases', icon: <Rocket /> },
              ],
            },
            { key: 'team', label: 'Team members', icon: <Users /> },
            { key: 'settings', label: 'Settings', icon: <Settings /> },
          ]}
        />
      );
    }
    

    More examples

    Horizontal navigation
    Collapsible sidebar
    advanced.tsx
    import type { MenuItem } from '@ifhover/leaf-ui';
    
    import { Button, Flex, Menu, Text } from '@ifhover/leaf-ui';
    
    import { BookOpen, Folder, House, Palette, Settings } from 'lucide-react';
    
    import { useState } from 'react';
    
    const items: MenuItem[] = [
      { key: 'home', label: 'Overview', icon: <House /> },
      {
        key: 'resources',
        label: 'Resources',
        icon: <Folder />,
        children: [
          { key: 'components', label: 'Components', icon: <BookOpen /> },
          { key: 'themes', label: 'Themes', icon: <Palette /> },
        ],
      },
      { key: 'settings', label: 'Settings', icon: <Settings /> },
    ];
    
    export function MenuHorizontal() {
      const [collapsed, setCollapsed] = useState(false);
      return (
        <Flex direction="column" gap={20}>
          <Flex direction="column" gap="sm" align="center">
            <Text tone="muted">Horizontal navigation</Text>
            <Menu mode="horizontal" items={items} defaultSelectedKey="home" />
          </Flex>
          <Flex direction="column" gap="sm" align="center">
            <Text tone="muted">Collapsible sidebar</Text>
            <Button variant="ghost" size="sm" onClick={() => setCollapsed((value) => !value)}>
              Toggle sidebar
            </Button>
            <Menu collapsed={collapsed} items={items} defaultSelectedKey="home" />
          </Flex>
        </Flex>
      );
    }
    

    Controlled navigation and routing

    Keep selectedKey in sync with the current route. Use linkRender to replace the default anchor with a React Router or Next.js Link, retaining its event handlers, classes and ARIA attributes.

    Current page: overview. The example updates local state; replace the anchor with your router Link and retain its props.
    capabilities.tsx
    import type { MenuItem } from '@ifhover/leaf-ui';
    
    import { Menu, Space, Text } from '@ifhover/leaf-ui';
    
    import { BookOpen, House, Settings } from 'lucide-react';
    
    import { type AnchorHTMLAttributes, cloneElement, isValidElement, type ReactElement, useState } from 'react';
    
    export function MenuRouting() {
      const [selected, setSelected] = useState('overview');
      const items: MenuItem[] = [
        { key: 'overview', label: 'Overview', href: '#overview', icon: <House /> },
        {
          key: 'resources',
          label: 'Resources',
          icon: <BookOpen />,
          children: [
            { key: 'guides', label: 'Guides', href: '#guides' },
            {
              key: 'settings',
              label: 'Settings',
              href: '#settings',
              icon: <Settings />,
            },
          ],
        },
      ];
      return (
        <Space direction="vertical" align="center">
          <Menu
            aria-label={'Application navigation'}
            items={items}
            selectedKey={selected}
            defaultOpenKeys={['resources']}
            onSelect={setSelected}
            linkRender={(_item, link) => {
              if (!isValidElement(link)) return link;
              const element = link as ReactElement<AnchorHTMLAttributes<HTMLAnchorElement>>;
              return cloneElement(element, {
                onClick: (event) => {
                  element.props.onClick?.(event);
                  event.preventDefault();
                },
              });
            }}
          />
          <Text tone="muted">
            {`Current page: ${selected}. The example updates local state; replace the anchor with your router Link and retain its props.`}
          </Text>
        </Space>
      );
    }
    

    Usage

    The vertical menu defaults to 240px (60px when collapsed); use style.width to customize it. items supports nesting, groups, dividers and links. selectedKey controls the current item and openKeys controls expanded items. Horizontal and collapsed modes display submenus in floating panels.

    Submenus animate in both directions, and the sidebar width transitions when collapsed. Closed items are excluded from keyboard navigation. Transitions are disabled when the system requests reduced motion.

    Menu items, hover backgrounds and selection highlights share the base radius with buttons. Set ConfigProvider's theme.borderRadius to adjust them together, or use theme.components.Menu.borderRadius to customize the menu radius.

    Types

    Import these types for data, callbacks and refs.

    import type { MenuItem, MenuProps } from '@ifhover/leaf-ui';
    PropertyTypeDefaultDescription
    keystringRequiredRequired. Unique stable identifier
    labelReactNodeRequiredRequired. Display label
    iconReactNode—Custom icon
    hrefstring—Destination URL
    disabledboolean—Disable interaction.
    dangerboolean—Danger colors
    childrenreadonly MenuItem[]—Content or child items
    type'item' | 'group' | 'divider'—Visual or item type
    PropertyTypeDefaultDescription
    itemsreadonly MenuItem[]RequiredRequired. Items; keep keys unique and stable
    mode'vertical' | 'horizontal' | 'inline''vertical'Menu orientation and behavior
    selectedKeystring—Controlled selected key
    defaultSelectedKeystring''Initial selected key
    onSelect(key: string, item: MenuItem) => void—Select an item
    openKeysreadonly string[]—Controlled open keys
    defaultOpenKeysreadonly string[][]Initially open keys
    onOpenChange(keys: string[]) => void—Open state changes
    collapsedbooleanfalseControlled collapsed state
    itemRender(item: MenuItem, content: ReactNode) => ReactNode—Customize item content.
    linkRender(item: MenuItem, link: ReactNode) => ReactNode—Render a router link while retaining supplied accessibility and event props.
    itemClassNamestring | ((item: MenuItem) => string)—Item class, or a class computed from an item.