MenuItem
메뉴 행 하나 — Menu, DropdownMenu, ContextMenu, Menubar, Select 가 함께 놓는 단위
목차
MenuItem 은 메뉴 패널 안 상호작용 행 하나입니다. Menu, DropdownMenu,
ContextMenu, Menubar, Select 가 모두 이 행을 놓기 때문에, 한 곳에서
그려서 다섯 컴포넌트가 같은 행을 갖게 합니다.
기본 사용법 (Basic Usage)#
MenuItem(
onPressed: () {},
label: const Text('Copy'),
shortcut: const Text('⌘C'),
leading: const Icon(LucideIcons.copy),
)
MenuItem(
onPressed: () {},
label: const Text('Copy'),
shortcut: const Text('⌘C'),
leading: const Icon(LucideIcons.copy),
)
Live Preview#
코드 보기
class MenuItemDefaultExample extends StatelessComponent {
const MenuItemDefaultExample({super.key});
@override
Component build(BuildContext context) {
// 행은 자기 폭을 정하지 않는다 — 메뉴 패널이 정한다. 프리뷰에서는
// 패널 폭 상한(`layout280`)을 부모가 대신 준다.
return div(
[
MenuItem(
onPressed: () {},
label: const Text('Copy'),
shortcut: const Text('⌘C'),
leading: const Icon(LucideIcons.copy),
),
],
classes: 'w-${CoreLayout.scale.layout280}',
);
}
}
class MenuItemDefaultExample extends StatelessWidget {
const MenuItemDefaultExample({super.key});
@override
Widget build(BuildContext context) {
// 행은 자기 폭을 정하지 않는다 — 메뉴 패널이 정한다. 프리뷰에서는
// 패널 폭 상한(`layout280`)을 부모가 대신 준다.
return SizedBox(
width: CoreLayout.layout280,
child: MenuItem(
onPressed: () {},
label: const Text('Copy'),
shortcut: const Text('⌘C'),
leading: const Icon(LucideIcons.copy),
),
);
}
}
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 커스텀 오버레이나 패널 안에 직접 메뉴 행을 조립할 때
Select옵션 목록처럼 다른 컴포넌트가 메뉴 행을 재사용할 때Menu가 합성하는 action / checkbox / radio 행의 기반 단위가 필요할 때
대신 다른 컴포넌트를 사용하세요:
-
Menu: 행 하나가 아니라 패널·항목 탐색을 목록으로 구성할 때 (
CoreMenuItem팩토리로 이 컴포넌트를 대신 합성해 줍니다) - Listing: 메뉴 행이 아니라 일반 행·열 콘텐츠 나열일 때
해부 (Anatomy)#
행은 시작부터 끝까지 다섯 좌석을 순서대로 배치합니다.
[ mark ] [ leading ] [ label / description ] [ shortcut | chevron ] [ trailing ]
-
mark — 체크박스의 체크, 라디오의 점처럼 켜짐을 나타내는 글리프.
mark가null이면 비어 있지만,reserveMark: true면 칸의 폭은 유지됩니다 — 토글 그룹 안에서 일부 행만 켜져도 라벨이 어긋나지 않도록. - leading — 임의 아이콘/인디케이터.
-
label / description —
label은 항상 있고,description이 있으면 두 줄이 됩니다(위쪽 정렬).description이 있는 행은 size 의 최소 높이를 넘어 자랍니다. -
shortcut | chevron — 키보드 단축키 힌트 또는(둘 중 하나만) 서브메뉴
셰브론(
hasSubmenu: true일 때). 서브메뉴가 있으면shortcut은 숨겨집니다 — 그 자리는 셰브론의 것입니다. - trailing — shortcut/chevron 뒤의 추가 슬롯.
좌석 사이 간격은 contentGapStyle, label 과 description 사이는
labelDescriptionGapStyle 이 각각 Gap 으로 그립니다.
Clickable + Text + Icon + Gap 으로 그려지며 Button
을 합성하지
않습니다 — 메뉴 행의 접근성 계약(메뉴 전체가 한 tab stop, roving focus,
행이 무엇인지에서 파생되는 menuitem* role, disabled 여도 focusable)이
버튼과 종류가 다르고 버튼의 chrome 으로는 표현할 수 없기 때문입니다.
축 (Axes) — 밀도와 톤#
size 와 tone 은 서로 다른 필드 집합을 결정하는 독립된 두 축입니다.
size 는 높이·여백·간격·모서리·타이포·아이콘 크기를 정하고, tone 은 전경색
하나만 바꿉니다.
밀도 (size) — 32 / 36 / 48#
size |
최소 높이 | padding (가로 / 세로) | 좌석 간격 | 모서리 | leading 아이콘 | label |
description |
shortcut |
|---|---|---|---|---|---|---|---|---|
sm |
32 | 8 / 6 | 8 | 8 | 16 | labelLarge |
bodyXs |
bodyXs |
md (기본) |
36 | 10 / 8 | 10 | 8 | 18 | labelLarge |
bodySmall |
bodyXs |
lg |
48 | 16 / 12 | 12 | 12 | 24 | labelXl |
bodyMedium |
bodySmall |
세 단만 있는 이유는 조사한 여섯 시스템 중 어느 것도 메뉴 행을 32 아래나
48 위로 그리지 않기 때문입니다 — xs / xl 을 선언하면 실제 범위를
넘어서는 축이 됩니다. 32 는 데스크톱 밀집 메뉴, 48 은 터치 타깃이고, 기본
36 은 컨트롤 사다리의 32 와 40 사이에 있어 이 메뉴를 여는 md 트리거
(Select / TextField, 40)보다 한 칸 낮게 앉습니다.
36 은 컨트롤 사다리의 단이 아니므로 밀도(CoreDensity)가 옮기지 않습니다.
sm · lg 행은 사다리 위의 단이라 spacious 에서는 한 단 위로(40 · 56), compact 에서는
lg 만 한 단 아래로(40) 움직입니다 — compact 는 사다리의 sm(32)에서 멈춥니다.
모서리는 행 높이 × 0.25 에 가장 가까운 CoreRadius 단입니다(8 / 8 / 12). md 는
36 × 0.25 = 9 가 단이 아니어서 8 입니다. 이 값은 혼자 선 행의 것입니다.
Menu (그리고 그것을 합성하는 DropdownMenu · ContextMenu
· Menubar) 와
Select 패널 안의 행은 사이즈와 무관하게 6 입니다 — 부모가 자기 행 슬롯
기본값(CoreMenuStyle.defaultItemStyle · CoreSelectStyle.defaultOptionStyle)에
6 을 적습니다. 안쪽 모서리는 감싼 패널보다 둥글면 안 되는데, 판 안쪽 여백이 6 이므로
패널 모서리 12 와 동심이 되는 행의 모서리가 6 이고(12 − 6), 행이 사이즈를 따르면
lg 행(12)이 패널 안에서 바깥만큼 둥글어지기 때문입니다.
mark 와 chevron 글리프는 이 사다리를 따라가지 않고 16 으로 고정입니다
— 광학적으로 같은 대역에 머물러야 라벨 정렬이 밀도마다 흔들리지 않기
때문입니다.
톤 (tone)#
tone | 전경색 | 쓰임 |
|---|---|---|
neutral (기본) | onSurface | 일반 액션 |
critical | error | 파괴적 액션 — 삭제처럼 되돌릴 수 없는 것 |
selected 채움은 두 tone 이 공유합니다. hover / focus / pressed 는 tone 이
다릅니다. neutral 은 전경색을 워시로 얹지만(상태 레이어 램프), critical
은
워시가 곧 에러 색 그 자체라 투명한 행 위에서 구분이 되지 않으므로 워시 대신
errorContainer 채움으로 읽힙니다. 글자색은 채움과 함께 바뀌지 않습니다 — 라벨 ·
글리프는 error, 설명 · 단축키는 쉬는 상태의 흐린 색 그대로입니다. 강제 색상 모드에서는 어차피 두 tone 이 한 색으로 접히므로 색이 유일한
단서인 만큼 배치 규약(그룹 마지막, 구분선 뒤)이 색과 함께 따라다닙니다.
Props / Parameters#
W 는 Flutter의 Widget / Web의 Jaspr Component입니다. 각 슬롯은 텍스트·아이콘뿐 아니라 같은 플랫폼의 임의 콘텐츠를 받습니다.
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
label |
W |
필수 |
행의 텍스트.
Text
chain 을 그대로 받는 composition slot — resolver 가 role(
labelLarge
/
labelXl
)을 공급합니다
|
size |
CoreMenuItemSize |
CoreMenuItemSize.defaultSize(md, 36px) |
밀도 — 32 / 36 / 48. 한 메뉴는 모든 행에 같은 값을 넘깁니다(Menu(size:)) |
tone |
CoreMenuItemTone |
CoreMenuItemTone.defaultTone(neutral) |
일반 또는 파괴적 액션. 전경색만 바뀝니다 |
description |
W? |
null |
label 아래 두 번째 줄. 있으면 행이 최소 높이를 넘어 자라고 두 줄이 위쪽 정렬됩니다 |
shortcut |
W? |
null |
행 끝의 키보드 단축키 힌트. hasSubmenu 면 숨겨집니다(그 자리는 셰브론) |
leading |
W? |
null |
시작 슬롯의 아이콘/인디케이터 |
trailing |
W? |
null |
shortcut/chevron 뒤의 추가 슬롯 |
mark |
W? |
null |
체크/라디오 같은 토글 글리프. 액션 행은 보통 null |
reserveMark |
bool |
false |
mark 가 null 이어도 mark 칸의 폭을 유지 — 토글 그룹의 라벨 정렬용 |
hasSubmenu |
bool |
false |
서브메뉴를 여는 행이면
true
. 셰브론(
LucideIcons.chevronRight
)을 그리고 Web 에서
aria-haspopup="menu"
를 답니다
|
selected |
bool |
false |
선택된 상태로 그릴지(활성 액션, 체크된 체크박스, 선택된 라디오) — 선택 배경/전경 |
enabled |
bool? |
null → onPressed != null |
활성화 가능 여부. null 이면 onPressed 유무로 유도됩니다. 비활성 행도 포커스는 받습니다(비활성 키보드 탐색 관행) |
onPressed |
void Function()? |
null |
활성화 콜백 |
menuItemStyle |
CoreMenuItemStyle? |
null |
모든 chrome 이 지나는 단일 슬롯 (아래 표 참고) |
스타일 시스템 (Style System)#
MenuItem 의 모든 chrome / dimensional 오버라이드는 단일 CoreMenuItemStyle
슬롯으로 흐릅니다. Menu 가 이 행을 합성할 때도 같은 슬롯을 통해
override 를 전달합니다(CoreMenuStyle.itemStyle).
시맨틱 vs 스타일#
-
시맨틱 / behaviour: 위젯 파라미터로 직접 (
size,tone,selected,enabled,hasSubmenu,reserveMark) -
chrome / dimensional:
CoreMenuItemStyle한 곳으로 (배경/전경 색, padding, 간격, radius, 아이콘/텍스트 스타일, 상태 레이어, 포커스 링)
defaultsBySize / defaultsByTone#
두 축의 기본값은 각각의 테이블이 소유합니다 — defaultsBySize 는 높이 ·
padding · 좌석 간격 · leading 아이콘 · label / description / shortcut 타이포를,
defaultsByTone 은 foregroundColor 하나만. 구체적인 값은 위
축
(Axes) 표에 있습니다. 나머지 필드(마크 · 셰브론 글리프,
모서리, 채움, 상태 레이어 램프, 합성된 Clickable chrome)는 두 축 어느
쪽에도 속하지 않는 default* 상수입니다.
Resolve chain#
CoreMenuItemStyle.defaultsBySize[size] // 밀도 기본값
→ CoreMenuItemStyle.defaultsByTone[tone] // 전경색 기본값
→ CoreMenuItemStyle.defaultX // size/tone 무관 기본값
→ CoreMenuItemTheme.style // 프로젝트 공통
→ widget.menuItemStyle // 인스턴스별
CoreMenuItemStyle 필드#
| 필드 | 타입 | 설명 |
|---|---|---|
minHeight |
double? |
Minimum row height (logical px). A description line grows past it.
null
→ the size ladder.
|
padding |
CoreEdgeInsets? |
Content insets. null → the size ladder. |
contentGapStyle |
CoreGapStyle? |
Gap between the mark, leading, text, shortcut / chevron and trailing seats.
null
→ the size ladder.
|
labelDescriptionGapStyle |
CoreGapStyle? |
Gap between the label and its description. null → [defaultLabelDescriptionGapStyle]. |
borderRadius |
CoreBorderRadius? |
Corner radius.
null
→ the size row's corner (
defaultsBySize[size].borderRadius
, the row height × 0.25). A host panel states its row corner here through its nested row slot.
|
leadingIconStyle |
CoreIconStyle? |
Leading icon chrome (size; colour follows the foreground). null → the size ladder. |
markIconStyle |
CoreIconStyle? |
Mark glyph chrome. null → [defaultMarkIconStyle]. |
chevronIconStyle |
CoreIconStyle? |
Submenu chevron chrome. null → [defaultChevronIconStyle]. |
labelStyle |
CoreTextStyle? |
Label typography (role; colour follows the foreground). null → the size ladder. |
descriptionStyle |
CoreTextStyle? |
Description typography and colour. null → the size ladder. |
shortcutTextStyle |
CoreTextStyle? |
Shortcut hint typography and colour. null → the size ladder. |
backgroundColor |
CoreColor? |
Resting fill. null → [defaultBackgroundColor]. |
foregroundColor |
CoreColor? |
Resting label / glyph colour. null → the tone table. |
selectedBackgroundColor |
CoreColor? |
Fill while the row is selected. null → [defaultSelectedBackgroundColor]. |
selectedForegroundColor |
CoreColor? |
Foreground while selected. null → [defaultSelectedForegroundColor]. |
disabledForegroundColor |
CoreColor? |
Foreground while disabled. null → [defaultDisabledForegroundColor]. |
hoverBackgroundColor |
CoreColor? |
Fill while the row is hovered or keyboard-focused.
null
→ the row paints no fill of its own for the state and the foreground is washed over the resting fill at [stateLayer]'s weight instead. Only a tone whose active state is a fill rather than a wash states it —
defaultsByTone[critical]
, where the wash colour would be the error ink itself. A selected or disabled row never reads it.
|
pressedBackgroundColor |
CoreColor? |
Fill while the row is pressed.
null
→ as [hoverBackgroundColor]. It takes effect only together with [hoverBackgroundColor].
|
activeForegroundColor |
CoreColor? |
Foreground while the row is hovered, focused or pressed — the label, the description, the shortcut and the glyphs.
null
→ the resting foreground. Stated with [hoverBackgroundColor] and [pressedBackgroundColor], since the ink has to be chosen for the fill it sits on.
|
stateLayer |
CoreStateLayer? |
How strongly the foreground is washed over the row on hover / focus / press.
null
→ [defaultStateLayer]. A tone that states an active fill takes no wash.
|
clickableStyle |
CoreClickableStyle? |
Nested chrome of the composed
Clickable
(focus ring, press feedback).
null
→ [defaultClickableStyle]. Raw-forwarded.
|
사용 예#
MenuItem(
onPressed: () {},
label: const Text('Copy'),
menuItemStyle: const CoreMenuItemStyle(
borderRadius: CoreBorderRadius.all(CoreRadius.radius12),
foregroundColor: CoreColor.token(CoreColors.secondary),
),
)
위젯 슬롯 — label / leading / mark 은 위젯 그대로#
label · description · shortcut · leading · trailing
· mark 은 전부
W? 슬롯이라 아이콘 · 인디케이터 · Text chain 을 그대로 받습니다(shadcn
asChild 패턴). 행은 그 위젯을 좌석에 놓기만 하고, 무엇을 놓을지는
호출자가 정합니다.
MenuItem(
onPressed: () {},
label: const Text('Sync'),
leading: const Icon(LucideIcons.refreshCw),
trailing: Text('Beta').labelSmall.onSurfaceVariant,
)
labelStyle · leadingIconStyle · markIconStyle 같은 nested 슬롯은 그
자리에 놓인 Text / Icon 의 chrome 미세 조정용입니다 — 색은 행의
상태(rest / selected / disabled)에서 오고 슬롯은 크기 · 굵기 같은 나머지를
정합니다. 슬롯 안 Text chain 에 직접 색을 얹으면 그 값이 행의 상태 색을
덮습니다.
빠른 오버라이드 (Chain)#
이미 만든 MenuItem 인스턴스에 스타일을 빠르게 덧붙이고 싶다면 withStyle
체인을 쓸 수 있습니다. 생성자의 style 슬롯 인자와 동일하게 동작하지만,
이미 구성된 위젯 위에서 바로 이어 쓸 수 있습니다.
class MenuItemChainExample extends StatelessWidget {
const MenuItemChainExample({super.key});
@override
Widget build(BuildContext context) {
return SizedBox(
width: CoreLayout.layout280,
child:
MenuItem(
onPressed: () {},
label: const Text('Copy'),
shortcut: const Text('⌘C'),
leading: const Icon(LucideIcons.copy),
).withStyle(
const CoreMenuItemStyle(
padding: CoreEdgeInsets.symmetric(
horizontal: CoreSpace.space16,
vertical: CoreSpace.space8,
),
contentGapStyle: CoreGapStyle(size: CoreSpace.space12),
foregroundColor: CoreColor.token(CoreColors.primary),
),
),
);
}
}
class MenuItemChainExample extends StatelessComponent {
const MenuItemChainExample({super.key});
@override
Component build(BuildContext context) {
return div(
[
MenuItem(
onPressed: () {},
label: const Text('Copy'),
shortcut: const Text('⌘C'),
leading: const Icon(LucideIcons.copy),
).withStyle(
const CoreMenuItemStyle(
padding: CoreEdgeInsets.symmetric(
horizontal: CoreSpace.space16,
vertical: CoreSpace.space8,
),
contentGapStyle: CoreGapStyle(size: CoreSpace.space12),
foregroundColor: CoreColor.token(CoreColors.primary),
),
),
],
classes: 'w-${CoreLayout.scale.layout280}',
);
}
}
변형 (Variants)#
설명 두 줄 (lg)#
MenuItem(
onPressed: () {},
size: CoreMenuItemSize.lg,
label: const Text('Archive'),
description: const Text('Move to the archive folder'),
leading: const Icon(LucideIcons.archive),
)
파괴적 액션 (critical)#
MenuItem(
onPressed: () {},
tone: CoreMenuItemTone.critical,
label: const Text('Delete'),
leading: const Icon(LucideIcons.trash2),
)
서브메뉴 트리거#
MenuItem(
onPressed: () {},
hasSubmenu: true,
label: const Text('Export'),
)
hasSubmenu: true 면 shortcut 자리에 셰브론(LucideIcons.chevronRight)이
자동으로 그려집니다 — shortcut 을 함께 넘겨도 무시됩니다.
체크박스 / 라디오 마크#
MenuItem(
onPressed: () {},
label: const Text('Show grid'),
mark: const Icon(LucideIcons.check),
selected: true,
)
동작 스펙 (Behavior)#
인터랙션#
- selected는 호출부의 표시 값이며 활성화가 이를 자동 토글하지 않습니다. hasSubmenu도 chevron·의미 표면만 정하고 서브메뉴의 열림·탐색은 호스트가 소유합니다.
-
클릭/탭:
enabled가true(또는onPressed가 non-null)일 때onPressed호출 -
호버 / 포커스 / 눌림: 행이 스스로 상태 레이어를 그립니다 — 전경색을
stateLayer알파(hover 8% / focus 8% / pressed 12%)로 워시합니다. 포커스가 hover 와 같은 강도인 이유는 실제 포커스 표시는 링이 담당하고 워시는 보조 신호이기 때문입니다.critical행은 워시 대신hoverBackgroundColor/pressedBackgroundColor채움과activeForegroundColor글자로 그립니다 — 선택된 행과 비활성 행에는 적용되지 않습니다 -
비활성화: 포커스는 받지만(비활성-focusable) 활성화는 무시되고
disabledForegroundColor로 그려집니다
색#
- rest:
tone표(defaultsByTone)의 전경색 -
selected:
selectedForegroundColor/selectedBackgroundColor(primary / onPrimary) -
disabled:
disabledForegroundColor— 기본값은disabledContent슬롯이며 라벨 · 설명 · 단축키 · 글리프가 모두 이 한 필드를 읽습니다 -
active (
critical의 hover / focus / pressed): 채움은hoverBackgroundColor·pressedBackgroundColor, 글자는activeForegroundColor -
아이콘 색은 전경을 따라갑니다 — resolver 가 상태별
CoreIconStyle을 내고 위젯이 고릅니다(leading / mark / chevron 각각 rest·selected·disabled·active)
포커스 링#
clickableStyle.focusOutlineStyle 경로로 그려집니다(합성된 Clickable 의
기본 포커스 링) — 행 자체의 모서리 반경(혼자 선 행은 8 / 8 / 12, 패널 안의 행은
6)을 따라갑니다.
사용 가이드라인 (Usage Guidelines)#
✅ Do#
한 메뉴 안에서는 같은 size 를 유지
Menu(
size: CoreMenuItemSize.sm,
items: [ /* 모든 행이 32px */ ],
)
Menu 는 자기 size 를 모든 행에 넘깁니다 — 행마다 다른 size 를 직접
지정하면 한 패널 안에서 높이가 들쭉날쭉해집니다.
❌ Don't#
파괴적 행을 그룹 중간에 두지 않기
// ❌ Delete 가 그룹 가운데 — 색만이 유일한 단서라 실수로 누르기 쉽다
MenuItem(tone: CoreMenuItemTone.critical, label: const Text('Delete'), onPressed: () {}),
MenuItem(label: const Text('Rename'), onPressed: () {}),
// ✅ 그룹 마지막, 구분선 뒤
Divider(),
MenuItem(tone: CoreMenuItemTone.critical, label: const Text('Delete'), onPressed: () {}),
tone 은 색만 바꾸고 배치는 바꾸지 않습니다 — 강제 색상 모드에서는 두
tone 이 같은 색으로 접힐 수 있으므로, 배치 규약(마지막에, 구분선 뒤)이
색과 함께 있어야 안전합니다.
접근성 (Accessibility)#
MenuItem 은 행 하나만 그립니다. 메뉴 전체의 roving tabindex, 화살표
탐색, 첫 글자 타이핑 점프, Home/End 는 이 행을 여러 개 합성하는 호스트
(Menu)가 소유합니다.
역할#
- Flutter — MenuRowScope가 없으면 button, Menu 아래이면 menuItem 역할·enabled·selected를 CoUISemantics로 노출합니다. 호스트가 역할을 직접 제공하는 scope이면 행의 자체 역할을 생략하며 이름은 슬롯 콘텐츠에서 옵니다.
-
Web — 기본 role 은
menuitem. 호스트(Menu)가 행의 종류에 따라attributes로role="menuitemcheckbox"+aria-checked또는role="menuitemradio"+aria-checked를 통과시킵니다.hasSubmenu이면aria-haspopup="menu"가 함께 붙습니다.
키보드#
| 키 | 동작 |
|---|---|
Enter / Space | 포커스된 행 활성화 |
Escape |
동작 취소는 이 컴포넌트가 아니라 오버레이 호스트(DropdownMenu/ContextMenu 등)의 몫 |
행 사이 이동(roving tabindex, 순환, Home/End, 문자 타이핑 점프)은
Menu 가 컨테이너 레벨에서 구현합니다 — MenuItem 단독으로는 다음/이전
행이라는 개념이 없습니다.
비활성 행도 포커스를 받습니다#
WAI-ARIA APG 권장대로, enabled: false 인 행도 키보드 탐색 순서에
남습니다(inert 지 invisible 이 아닙니다) — Web 은 aria-disabled="true"
를 달고 활성화만 무시합니다.
스크린 리더#
이름은 label 슬롯 콘텐츠에서 옵니다. 선택·비활성·서브메뉴 상태는 행이
전달하고, checkbox / radio 행의 체크 의미는 호스트 Menu 가 함께 실어 줍니다.
단축키 슬롯은 표시 텍스트이며 실제 단축키를 등록하지 않습니다.
포커스 관리#
행 하나는 자동 포커스·트랩·닫힘 후 복귀를 소유하지 않습니다. 포커스 링은
합성된 Clickable 이, 행 사이 탐색과 오버레이 복귀는 호스트가 관리합니다.
알려진 제약#
아이콘만 있는 label 의 이름을 자동 생성하지 않습니다. 이 행을 단독으로
여러 개 나열해도 메뉴 탐색이 생기지 않으므로 목록에는 Menu 를 쓰세요.
shortcut 문구만으로 키보드 단축키가 실행되지는 않습니다.
크로스 플랫폼 차이점 (Platform Differences)#
| 항목 | Flutter | Web |
|---|---|---|
| 클래스명 | MenuItem | MenuItem |
| 렌더 | Clickable + Text + Icon + Gap |
Clickable + Text + Icon + Gap |
| 역할 | 독립 행 button / MenuRowScope 안 menuItem | menuitem (호스트가 checkbox / radio / option으로 덮을 수 있음) |
| 상태 레이어 |
Clickable.onHover
/
onFocus
/
onPressedChange
로 감지 + resolver per-state 값 select
|
CSS hover:/focus-visible:/active: pseudo + emit family |
관련 컴포넌트 (Related Components)#
-
Menu: 정적 메뉴 패널 —
CoreMenuItem팩토리로 이 컴포넌트를 대신 합성합니다 - DropdownMenu: 트리거로 떠오르는 오버레이 메뉴
- ContextMenu: 우클릭/롱프레스 컨텍스트 메뉴
- Menubar: 가로 애플리케이션 메뉴바
- Select: 폼 값을 고르는 드롭다운 — 옵션 행에 같은 컴포넌트를 재사용합니다