컴포넌트

Menu

버튼을 눌러 작업 목록을 엽니다.

설치

pnpm dlx ply-ui add menu icon

공통 설치 설정을 먼저 적용합니다.

사용법

버튼을 눌러 작업 목록을 열 때 사용합니다. Item.onClick에 작업을 연결합니다. 값을 선택하는 입력은 Select를 사용합니다.

구성

구성 요소역할
Root메뉴의 열림 상태를 관리합니다.
Trigger메뉴를 여는 버튼입니다.
Portal / Positioner메뉴를 별도 영역에 렌더하고 버튼을 기준으로 배치합니다.
Popup목록의 표면입니다. size의 기본값은 md입니다.
Item하나의 작업입니다. onClick으로 동작을 연결합니다.
Group / GroupLabel / Separator관련 작업을 묶거나 구분합니다.
SubmenuRoot / SubmenuTrigger하위 메뉴의 상태와 여는 항목을 구성합니다.
CheckboxItem / CheckboxItemIndicator서로 독립적인 켜짐·꺼짐 항목과 선택 표시입니다.
RadioGroup / RadioItem / RadioItemIndicator여러 값 중 하나를 선택하는 항목과 선택 표시입니다.

크기 XS

Popup size="xs"로 목록 항목의 글자 크기와 여백을 지정합니다.

크기 SM

Popup size="sm"로 목록 항목의 글자 크기와 여백을 지정합니다.

크기 MD

Popup size="md"로 목록 항목의 글자 크기와 여백을 지정합니다. Menu의 기본값입니다.

크기 LG

Popup size="lg"로 목록 항목의 글자 크기와 여백을 지정합니다.

체크 항목

CheckboxItem은 켜짐과 꺼짐을 전환합니다. checkedonCheckedChange를 연결합니다.

비활성 항목

작업 하나만 사용할 수 없을 때는 해당 Itemdisabled를 지정합니다.

하나의 설정 선택

RadioGroup이 선택값을 관리합니다. 그룹 안의 RadioItem마다 고유한 값을 지정합니다.

하위 메뉴

SubmenuRoot 안에 SubmenuTrigger와 하위 Popup을 구성합니다. 오른쪽 방향키로 하위 메뉴에 들어갈 수 있습니다.

속성

이 프로젝트에서 추가하거나 제한한 속성입니다.

속성

타입

구현 코드

components/ui/menu.tsx
menu.tsx
"use client";

import type { ComponentProps } from "react";
import { Menu as Primitive } from "@base-ui/react/menu";
import { withClassName } from "../../lib/cx";
import "./menu.css";

// 동작과 접근성은 Base UI가 담당합니다. 이 파일은 스타일 연결만 담당합니다.
function MenuTrigger({
  className,
  ...props
}: ComponentProps<typeof Primitive.Trigger>) {
  return (
    <Primitive.Trigger
      {...props}
      className={withClassName("rbx-button", className)}
    />
  );
}

export type MenuPopupProps = ComponentProps<typeof Primitive.Popup> & {
  /** 목록 항목의 글자 크기와 여백입니다. @defaultValue "md" */
  size?: "xs" | "sm" | "md" | "lg";
};
function MenuPopup({ size = "md", className, ...props }: MenuPopupProps) {
  return (
    <Primitive.Popup
      {...props}
      data-size={size}
      className={withClassName("rbx-popup", className)}
    />
  );
}

function MenuPositioner({
  className,
  ...props
}: ComponentProps<typeof Primitive.Positioner>) {
  return (
    <Primitive.Positioner
      {...props}
      className={withClassName("rbx-positioner", className)}
    />
  );
}

function MenuItem({
  className,
  ...props
}: ComponentProps<typeof Primitive.Item>) {
  return (
    <Primitive.Item
      {...props}
      className={withClassName("rbx-option", className)}
    />
  );
}

function MenuSubmenuTrigger({
  className,
  ...props
}: ComponentProps<typeof Primitive.SubmenuTrigger>) {
  return (
    <Primitive.SubmenuTrigger
      {...props}
      className={withClassName("rbx-option", className)}
    />
  );
}

function MenuGroupLabel({
  className,
  ...props
}: ComponentProps<typeof Primitive.GroupLabel>) {
  return (
    <Primitive.GroupLabel
      {...props}
      className={withClassName("rbx-group-label", className)}
    />
  );
}

function MenuCheckboxItem({
  className,
  ...props
}: ComponentProps<typeof Primitive.CheckboxItem>) {
  return (
    <Primitive.CheckboxItem
      {...props}
      className={withClassName("rbx-option", className)}
    />
  );
}

function MenuCheckboxItemIndicator({
  className,
  ...props
}: ComponentProps<typeof Primitive.CheckboxItemIndicator>) {
  return (
    <Primitive.CheckboxItemIndicator
      {...props}
      className={withClassName("rbx-option-indicator", className)}
    />
  );
}

function MenuRadioItem({
  className,
  ...props
}: ComponentProps<typeof Primitive.RadioItem>) {
  return (
    <Primitive.RadioItem
      {...props}
      className={withClassName("rbx-option", className)}
    />
  );
}

function MenuRadioItemIndicator({
  className,
  ...props
}: ComponentProps<typeof Primitive.RadioItemIndicator>) {
  return (
    <Primitive.RadioItemIndicator
      {...props}
      className={withClassName("rbx-option-indicator", className)}
    />
  );
}

function MenuSeparator({
  className,
  ...props
}: ComponentProps<typeof Primitive.Separator>) {
  return (
    <Primitive.Separator
      {...props}
      className={withClassName("rbx-separator", className)}
    />
  );
}

// Root/Portal 등 스타일 없는 파트와 제네릭 API는 원본을 그대로 보존합니다.
export const Menu = {
  ...Primitive,
  Separator: MenuSeparator,
  Trigger: MenuTrigger,
  Popup: MenuPopup,
  Positioner: MenuPositioner,
  Item: MenuItem,
  SubmenuTrigger: MenuSubmenuTrigger,
  GroupLabel: MenuGroupLabel,
  CheckboxItem: MenuCheckboxItem,
  CheckboxItemIndicator: MenuCheckboxItemIndicator,
  RadioItem: MenuRadioItem,
  RadioItemIndicator: MenuRadioItemIndicator,
};
components/ui/menu.css
menu.css
@import "./button.css";
/* Menu: 공통 구조는 theme.css, 컴포넌트 전용 조정은 아래에 작성합니다. */

목차