Menubar

Menubar는 데스크톱 앱에서 흔히 볼 수 있는 것처럼, 자주 쓰는 명령들의 일관된 집합을 제공하는 시각적으로 상시 표시되는 메뉴를 만들기 위한 React 컴포넌트예요. 접근성이 뛰어난 애플리케이션 메뉴를 간편하게 구성할 수 있어요.

출처: 문서

본문

메뉴바는 데스크톱 애플리케이션에서 흔히 볼 수 있는 것과 유사한, 자주 쓰는 명령들의 일관된 집합을 제공하는 상시 표시 메뉴예요.

Material UI는 메뉴바 컴포넌트를 기본으로 제공하지는 않지만, 이 페이지에서는 Base UI Menubar로 구성하고 Material Design(MD2) 명세에 맞춰 스타일링한 컴포넌트들을 소개해요. 그래서 Material UI와 함께 사용할 수 있어요.

따라서 진행하기 전에 Base UI를 설치해야 해요. 아래 예시들은 그대로 복사해서 앱에 붙여넣으면 돼요. Base UI는 tree-shakeable이라 최종 번들에는 프로젝트에서 실제로 사용하는 컴포넌트만 포함돼요.

npm install @base-ui/react
pnpm add @base-ui/react
yarn add @base-ui/react

사용법 (Usage)

  1. 아래 데모 중 시각적 디자인에 맞는 것을 하나 고르세요.
  2. 툴바에서 Expand code를 클릭하세요.
  3. ./Menubar로 시작하는 파일을 선택하세요.
  4. 코드를 복사해서 프로젝트에 붙여넣으세요.

기본 메뉴바 (Basic menubar)

기본 메뉴바 컴포넌트는 메뉴 항목들을 담은 드롭다운을 가진 메뉴 트리거들의 한 줄을 표시해요.

import * as React from 'react';
import {
  Menubar,
  MenuRoot,
  MenuTrigger,
  MenuPortal,
  MenuPositioner,
  MenuPopup,
  MenuItem,
  MenuSeparator,
  MenuSubmenuRoot,
  MenuSubmenuTrigger,
} from './components/Menubar';

export default function BasicMenubar() {
  return (
    <Menubar>
      <MenuRoot>
        <MenuTrigger>File</MenuTrigger>
        <MenuPortal>
          <MenuPositioner sideOffset={4} alignOffset={-2}>
            <MenuPopup>
              <MenuItem>New</MenuItem>
              <MenuItem>Open…</MenuItem>
              <MenuItem>Save</MenuItem>
              <MenuItem>Save as…</MenuItem>
              <MenuSeparator />
              <MenuSubmenuRoot>
                <MenuSubmenuTrigger>Share</MenuSubmenuTrigger>
                <MenuPortal>
                  <MenuPositioner alignOffset={-4}>
                    <MenuPopup>
                      <MenuItem>Email link</MenuItem>
                      <MenuItem>Copy link</MenuItem>
                    </MenuPopup>
                  </MenuPositioner>
                </MenuPortal>
              </MenuSubmenuRoot>
              <MenuSeparator />
              <MenuItem>Close</MenuItem>
            </MenuPopup>
          </MenuPositioner>
        </MenuPortal>
      </MenuRoot>

      <MenuRoot>
        <MenuTrigger>Help</MenuTrigger>
        <MenuPortal>
          <MenuPositioner sideOffset={4}>
            <MenuPopup>
              <MenuItem>Documentation</MenuItem>
              <MenuItem>Release notes</MenuItem>
              <MenuSeparator />
              <MenuItem>About</MenuItem>
            </MenuPopup>
          </MenuPositioner>
        </MenuPortal>
      </MenuRoot>
    </Menubar>
  );
}

단축키 힌트 (Shortcut hints)

hint prop을 사용해서 메뉴 항목 옆에 키보드 단축키를 표시할 수 있어요.

import * as React from 'react';
import {
  Menubar,
  MenuRoot,
  MenuTrigger,
  MenuPortal,
  MenuPositioner,
  MenuPopup,
  MenuItem,
  MenuSeparator,
} from './components/Menubar';

export default function ShortcutHintsMenubar() {
  return (
    <Menubar>
      <MenuRoot>
        <MenuTrigger>File</MenuTrigger>
        <MenuPortal>
          <MenuPositioner sideOffset={4} alignOffset={-2}>
            <MenuPopup>
              <MenuItem hint="⌘N">New</MenuItem>
              <MenuItem hint="⌘O">Open…</MenuItem>
              <MenuItem hint="⌘S">Save</MenuItem>
              <MenuItem hint="⇧⌘S">Save As…</MenuItem>
              <MenuSeparator />
              <MenuItem hint="⌘P">Print…</MenuItem>
            </MenuPopup>
          </MenuPositioner>
        </MenuPortal>
      </MenuRoot>

      <MenuRoot>
        <MenuTrigger>Edit</MenuTrigger>
        <MenuPortal>
          <MenuPositioner sideOffset={4} alignOffset={-2}>
            <MenuPopup>
              <MenuItem hint="⌘Z">Undo</MenuItem>
              <MenuItem hint="⇧⌘Z">Redo</MenuItem>
              <MenuSeparator />
              <MenuItem hint="⌘X">Cut</MenuItem>
              <MenuItem hint="⌘C">Copy</MenuItem>
              <MenuItem hint="⌘V">Paste</MenuItem>
            </MenuPopup>
          </MenuPositioner>
        </MenuPortal>
      </MenuRoot>
    </Menubar>
  );
}

체크박스 항목 (Checkbox items)

각각 독립적으로 켜고 끌 수 있는 토글 옵션을 만들 때 사용해요.

import * as React from 'react';
import {
  Menubar,
  MenuRoot,
  MenuTrigger,
  MenuPortal,
  MenuPositioner,
  MenuPopup,
  MenuItem,
  MenuCheckboxItem,
  MenuSeparator,
} from './components/Menubar';

export default function CheckboxItemsMenubar() {
  const [showSidebar, setShowSidebar] = React.useState(true);
  const [showToolbar, setShowToolbar] = React.useState(true);
  const [showStatusBar, setShowStatusBar] = React.useState(false);
  const [googleTasks, setGoogleTasks] = React.useState(true);
  const [mail, setMail] = React.useState(false);
  const [messages, setMessages] = React.useState(false);

  return (
    <Menubar>
      <MenuRoot>
        <MenuTrigger>View</MenuTrigger>
        <MenuPortal>
          <MenuPositioner sideOffset={4} alignOffset={-2}>
            <MenuPopup>
              <MenuCheckboxItem
                checked={showSidebar}
                onCheckedChange={setShowSidebar}
              >
                Show Sidebar
              </MenuCheckboxItem>
              <MenuCheckboxItem
                checked={showToolbar}
                onCheckedChange={setShowToolbar}
              >
                Show Toolbar
              </MenuCheckboxItem>
              <MenuCheckboxItem
                checked={showStatusBar}
                onCheckedChange={setShowStatusBar}
              >
                Show Status Bar
              </MenuCheckboxItem>
            </MenuPopup>
          </MenuPositioner>
        </MenuPortal>
      </MenuRoot>

      <MenuRoot>
        <MenuTrigger>Window</MenuTrigger>
        <MenuPortal>
          <MenuPositioner sideOffset={4} alignOffset={-2}>
            <MenuPopup>
              <MenuItem hint="⌘M">Minimize</MenuItem>
              <MenuItem>Zoom</MenuItem>
              <MenuItem hint="⌃⌥F">Fill</MenuItem>
              <MenuItem hint="⌃⌥C">Center</MenuItem>
              <MenuSeparator />
              <MenuItem>Bring All to Front</MenuItem>
              <MenuSeparator />
              <MenuCheckboxItem
                checked={googleTasks}
                onCheckedChange={setGoogleTasks}
              >
                Google Tasks - Tasks
              </MenuCheckboxItem>
              <MenuCheckboxItem checked={mail} onCheckedChange={setMail}>
                Mail
              </MenuCheckboxItem>
              <MenuCheckboxItem checked={messages} onCheckedChange={setMessages}>
                Messages
              </MenuCheckboxItem>
            </MenuPopup>
          </MenuPositioner>
        </MenuPortal>
      </MenuRoot>
    </Menubar>
  );
}

라디오 그룹 항목 (Radio group items)

한 번에 하나만 선택할 수 있는 상호 배타적인 옵션을 만들 때 사용해요.

import * as React from 'react';
import {
  Menubar,
  MenuRoot,
  MenuTrigger,
  MenuPortal,
  MenuPositioner,
  MenuPopup,
  MenuRadioGroup,
  MenuRadioItem,
  MenuSeparator,
  MenuSubmenuRoot,
  MenuSubmenuTrigger,
} from './components/Menubar';

export default function RadioGroupItemsMenubar() {
  const [theme, setTheme] = React.useState('system');
  const [density, setDensity] = React.useState('compact');

  return (
    <Menubar>
      <MenuRoot>
        <MenuTrigger>Appearance</MenuTrigger>
        <MenuPortal>
          <MenuPositioner sideOffset={4} alignOffset={-2}>
            <MenuPopup>
              <MenuSubmenuRoot>
                <MenuSubmenuTrigger>Theme</MenuSubmenuTrigger>
                <MenuPortal>
                  <MenuPositioner alignOffset={-4}>
                    <MenuPopup>
                      <MenuRadioGroup value={theme} onValueChange={setTheme}>
                        <MenuRadioItem value="light">Light</MenuRadioItem>
                        <MenuRadioItem value="dark">Dark</MenuRadioItem>
                        <MenuRadioItem value="system">System</MenuRadioItem>
                      </MenuRadioGroup>
                    </MenuPopup>
                  </MenuPositioner>
                </MenuPortal>
              </MenuSubmenuRoot>
              <MenuSeparator />
              <MenuRadioGroup value={density} onValueChange={setDensity}>
                <MenuRadioItem value="compact">Compact</MenuRadioItem>
                <MenuRadioItem value="comfortable">Comfortable</MenuRadioItem>
              </MenuRadioGroup>
            </MenuPopup>
          </MenuPositioner>
        </MenuPortal>
      </MenuRoot>
    </Menubar>
  );
}

아이콘 메뉴 항목 (Icon menu items)

icon prop을 써서 메뉴 항목에 아이콘을 추가하면 시각적으로 더 빨리 인식할 수 있어요.

import * as React from 'react';
import AddIcon from '@mui/icons-material/Add';
import FolderOpenIcon from '@mui/icons-material/FolderOpen';
import SaveIcon from '@mui/icons-material/Save';
import PrintIcon from '@mui/icons-material/Print';
import UndoIcon from '@mui/icons-material/Undo';
import RedoIcon from '@mui/icons-material/Redo';
import {
  Menubar,
  MenuRoot,
  MenuTrigger,
  MenuPortal,
  MenuPositioner,
  MenuPopup,
  MenuItem,
  MenuSeparator,
} from './components/Menubar';

export default function IconItemsMenubar() {
  return (
    <Menubar>
      <MenuRoot>
        <MenuTrigger>File</MenuTrigger>
        <MenuPortal>
          <MenuPositioner sideOffset={4} alignOffset={-2}>
            <MenuPopup>
              <MenuItem icon={<AddIcon fontSize="small" />}>New</MenuItem>
              <MenuItem icon={<FolderOpenIcon fontSize="small" />}>Open…</MenuItem>
              <MenuItem icon={<SaveIcon fontSize="small" />}>Save</MenuItem>
              <MenuSeparator />
              <MenuItem icon={<PrintIcon fontSize="small" />}>Print…</MenuItem>
            </MenuPopup>
          </MenuPositioner>
        </MenuPortal>
      </MenuRoot>

      <MenuRoot>
        <MenuTrigger>Edit</MenuTrigger>
        <MenuPortal>
          <MenuPositioner sideOffset={4} alignOffset={-2}>
            <MenuPopup>
              <MenuItem icon={<UndoIcon fontSize="small" />}>Undo</MenuItem>
              <MenuItem icon={<RedoIcon fontSize="small" />}>Redo</MenuItem>
            </MenuPopup>
          </MenuPositioner>
        </MenuPortal>
      </MenuRoot>
    </Menubar>
  );
}

그룹 라벨 (Group labels)

메뉴 항목들을 라벨이 있는 그룹으로 묶어 논리적인 섹션으로 정리할 수 있어요.

import * as React from 'react';
import InfoIcon from '@mui/icons-material/Info';
import SettingsIcon from '@mui/icons-material/Settings';
import BuildIcon from '@mui/icons-material/Build';
import MonitorHeartIcon from '@mui/icons-material/MonitorHeart';
import TimelineIcon from '@mui/icons-material/Timeline';
import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile';
import ToggleOnIcon from '@mui/icons-material/ToggleOn';
import TuneIcon from '@mui/icons-material/Tune';
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff';
import VisibilityIcon from '@mui/icons-material/Visibility';
import UndoIcon from '@mui/icons-material/Undo';
import RedoIcon from '@mui/icons-material/Redo';
import ContentCutIcon from '@mui/icons-material/ContentCut';
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import ContentPasteIcon from '@mui/icons-material/ContentPaste';
import {
  Menubar,
  MenuRoot,
  MenuTrigger,
  MenuPortal,
  MenuPositioner,
  MenuPopup,
  MenuItem,
  MenuSeparator,
  MenuSubmenuRoot,
  MenuSubmenuTrigger,
  MenuGroup,
  MenuGroupLabel,
} from './components/Menubar';

export default function GroupLabelMenubar() {
  return (
    <Menubar>
      <MenuRoot>
        <MenuTrigger>App</MenuTrigger>
        <MenuPortal>
          <MenuPositioner sideOffset={4} alignOffset={-2}>
            <MenuPopup>
              <MenuGroup>
                <MenuGroupLabel>General</MenuGroupLabel>
                <MenuItem icon={<InfoIcon fontSize="small" />}>About</MenuItem>
                <MenuItem icon={<SettingsIcon fontSize="small" />}>
                  Settings...
                </MenuItem>
              </MenuGroup>
              <MenuSeparator />
              <MenuSubmenuRoot>
                <MenuSubmenuTrigger icon={<BuildIcon fontSize="small" />}>
                  Services
                </MenuSubmenuTrigger>
                <MenuPortal>
                  <MenuPositioner alignOffset={-4}>
                    <MenuPopup>
                      <MenuGroup>
                        <MenuGroupLabel>Development</MenuGroupLabel>
                        <MenuItem icon={<MonitorHeartIcon fontSize="small" />}>
                          Activity Monitor
                        </MenuItem>
                        <MenuItem icon={<TimelineIcon fontSize="small" />}>
                          System Trace
                        </MenuItem>
                        <MenuItem icon={<InsertDriveFileIcon fontSize="small" />}>
                          File Activity
                        </MenuItem>
                      </MenuGroup>
                      <MenuSeparator />
                      <MenuGroup>
                        <MenuGroupLabel>Shortcuts</MenuGroupLabel>
                        <MenuItem icon={<ToggleOnIcon fontSize="small" />}>
                          Toggle Gate
                        </MenuItem>
                        <MenuItem icon={<TuneIcon fontSize="small" />}>
                          Services Settings...
                        </MenuItem>
                      </MenuGroup>
                    </MenuPopup>
                  </MenuPositioner>
                </MenuPortal>
              </MenuSubmenuRoot>
              <MenuSeparator />
              <MenuGroup>
                <MenuGroupLabel>Window</MenuGroupLabel>
                <MenuItem icon={<VisibilityOffIcon fontSize="small" />}>
                  Hide App
                </MenuItem>
                <MenuItem icon={<VisibilityOffIcon fontSize="small" />}>
                  Hide Others
                </MenuItem>
                <MenuItem icon={<VisibilityIcon fontSize="small" />}>
                  Show All
                </MenuItem>
              </MenuGroup>
            </MenuPopup>
          </MenuPositioner>
        </MenuPortal>
      </MenuRoot>

      <MenuRoot>
        <MenuTrigger>Edit</MenuTrigger>
        <MenuPortal>
          <MenuPositioner sideOffset={4}>
            <MenuPopup>
              <MenuGroup>
                <MenuGroupLabel>History</MenuGroupLabel>
                <MenuItem icon={<UndoIcon fontSize="small" />}>Undo</MenuItem>
                <MenuItem icon={<RedoIcon fontSize="small" />}>Redo</MenuItem>
              </MenuGroup>
              <MenuSeparator />
              <MenuGroup>
                <MenuGroupLabel>Clipboard</MenuGroupLabel>
                <MenuItem icon={<ContentCutIcon fontSize="small" />}>Cut</MenuItem>
                <MenuItem icon={<ContentCopyIcon fontSize="small" />}>Copy</MenuItem>
                <MenuItem icon={<ContentPasteIcon fontSize="small" />}>
                  Paste
                </MenuItem>
              </MenuGroup>
            </MenuPopup>
          </MenuPositioner>
        </MenuPortal>
      </MenuRoot>
    </Menubar>
  );
}

Base UI API

모든 props에 대한 전체 참조는 아래 문서를 확인하세요.

더 알아보기 (Learn more)