Skip to main content
useMenu is a React hook that generates menu items based on your defined resources. It’s commonly used to build navigation menus and sidebars, automatically creating menu items with proper routes and labels.

Usage

import { useMenu } from "@refinedev/core";

const CustomSidebar = () => {
  const { menuItems, selectedKey, defaultOpenKeys } = useMenu();

  return (
    <nav>
      {menuItems.map((item) => (
        <a key={item.key} href={item.route}>
          {item.icon}
          {item.label}
        </a>
      ))}
    </nav>
  );
};

Parameters

Return Values

menuItems
TreeMenuItem[]
Array of menu items generated from your resources. Each item includes:
key
string
Unique identifier for the menu item.
name
string
Resource name.
label
string
Display label for the menu item (from meta.label or translated resource name).
route
string
URL path for the menu item.
icon
React.ReactNode
Icon element from resource meta.
children
TreeMenuItem[]
Nested menu items (for resources with parent relationships).
selectedKey
string
The key of the currently active menu item, based on the current route and resource.
defaultOpenKeys
string[]
Array of keys that should be expanded by default, including the current resource and all its parent resources.

Examples

Basic Menu

import { useMenu } from "@refinedev/core";

const Sidebar = () => {
  const { menuItems } = useMenu();

  return (
    <aside>
      <ul>
        {menuItems.map((item) => (
          <li key={item.key}>
            <a href={item.route}>
              {item.icon}
              <span>{item.label}</span>
            </a>
          </li>
        ))}
      </ul>
    </aside>
  );
};
import { useMenu } from "@refinedev/core";

const Sidebar = () => {
  const { menuItems, selectedKey } = useMenu();

  return (
    <nav>
      <ul>
        {menuItems.map((item) => (
          <li
            key={item.key}
            className={item.key === selectedKey ? "active" : ""}
          >
            <a href={item.route}>
              {item.icon}
              {item.label}
            </a>
          </li>
        ))}
      </ul>
    </nav>
  );
};

Nested Menu with Children

import { useMenu } from "@refinedev/core";

const MenuItem = ({ item, selectedKey }) => {
  const hasChildren = item.children.length > 0;

  return (
    <li>
      <a
        href={item.route}
        className={item.key === selectedKey ? "active" : ""}
      >
        {item.icon}
        {item.label}
      </a>
      {hasChildren && (
        <ul>
          {item.children.map((child) => (
            <MenuItem
              key={child.key}
              item={child}
              selectedKey={selectedKey}
            />
          ))}
        </ul>
      )}
    </li>
  );
};

const Sidebar = () => {
  const { menuItems, selectedKey } = useMenu();

  return (
    <nav>
      <ul>
        {menuItems.map((item) => (
          <MenuItem key={item.key} item={item} selectedKey={selectedKey} />
        ))}
      </ul>
    </nav>
  );
};

Collapsible Menu

import { useMenu } from "@refinedev/core";
import { useState } from "react";

const Sidebar = () => {
  const { menuItems, selectedKey, defaultOpenKeys } = useMenu();
  const [openKeys, setOpenKeys] = useState(defaultOpenKeys);

  const toggleItem = (key: string) => {
    setOpenKeys((prev) =>
      prev.includes(key)
        ? prev.filter((k) => k !== key)
        : [...prev, key]
    );
  };

  return (
    <nav>
      <ul>
        {menuItems.map((item) => (
          <li key={item.key}>
            <div onClick={() => toggleItem(item.key)}>
              {item.icon}
              {item.label}
            </div>
            {openKeys.includes(item.key) && item.children.length > 0 && (
              <ul>
                {item.children.map((child) => (
                  <li key={child.key}>
                    <a href={child.route}>{child.label}</a>
                  </li>
                ))}
              </ul>
            )}
          </li>
        ))}
      </ul>
    </nav>
  );
};

With Custom Meta

import { useMenu } from "@refinedev/core";

const Sidebar = () => {
  const { menuItems } = useMenu({
    meta: {
      tenant: "company-1",
    },
  });

  return (
    <nav>
      <ul>
        {menuItems.map((item) => (
          <li key={item.key}>
            <a href={item.route}>{item.label}</a>
          </li>
        ))}
      </ul>
    </nav>
  );
};

API Reference

Type definitions:
export type UseMenuProps = {
  meta?: Record<string, any>;
  hideOnMissingParameter?: boolean;
};

export type TreeMenuItem = {
  key: string;
  name: string;
  label?: string;
  route?: string;
  icon?: React.ReactNode;
  children: TreeMenuItem[];
};

type UseMenuReturnType = {
  defaultOpenKeys: string[];
  selectedKey: string;
  menuItems: TreeMenuItem[];
};
Menu items are automatically generated from resources defined in your <Refine> component. Resources with a list property will appear in the menu.
Use the meta.hide property on a resource to exclude it from the menu, or meta.label to customize the display text.

Build docs developers (and LLMs) love