callstack / callstack/react-native-paper

feat: modernize Menu to the latest Material Design specs

Open
#4,977 0 comments 0 reactions 0 assignees View on GitHub
v6
Dominant language
TypeScript
Stars
14.5k
Forks
2.2k
Avg merge
5d 23h
Merged PRs (30d)
12

Description

- Modernize the Menu component to the latest specs. Reuse the newly introduced theme tokens (typography, motion, shape etc).
See https://m3.material.io/components/menus for the full picture.
- Extract component specific tokens for easier maintenance.
- Get inspired from TextInput/TextField, Switch, Checkbox, FAB components which have gone through modernization.

# Current State

## Menu

**MD3 spec:** Menus
**Specs link:** https://m3.material.io/components/menus/specs

### Color tokens

- Container background: `theme.colors.elevation[level2]` which resolves to `surfaceContainerLow` ✅ (standard color scheme)
- `Menu.Item` label text: `onSurface` ✅
- `Menu.Item` leading/trailing icon: `onSurfaceVariant` ✅
- `Menu.Item` disabled opacity: `stateOpacity.disabled` (0.38) ✅
- [ ] No selected item state: spec defines `tertiaryContainer` bg / `onTertiaryContainer` text+icon for selected menu items
- [ ] No vibrant color scheme (M3 Expressive): `tertiaryContainer` container / `onTertiaryContainer` icons+labels / `tertiary` selected bg / `onTertiary` selected text+icon

### Spacing / sizing

- Container `paddingVertical: 8` ✅
- Item min/max width: 112dp / 280dp ✅
- Item `paddingHorizontal: 12` ✅
- Icon leading margin: 12dp after icon ✅
- Item height: 48dp (standard), 32dp (dense) – baseline menu values ✅
- [ ] `Menu.Item` label text uses `bodyLarge`; spec requires `labelLarge`
- [ ] `Menu.Item` has no supporting text slot (`bodySmall`); spec anatomy includes optional supporting text per item
- [ ] `Menu.Item` has no trailing supporting text slot (`labelLarge`); spec anatomy includes optional trailing text per item

### Shape

- [ ] Container: `borderRadius: theme.roundness` = 4dp; spec `corner.large` = `4 * roundness` = 16dp ❌
- [ ] First child item: spec `corner.medium` top corners; not implemented
- [ ] Last child item: spec `corner.medium` bottom corners; not implemented
- [ ] Selected item: spec `corner.medium`; not implemented
- No per-item shape rounding at all; all items are rectangles

### Behavior

- Open/close: scale + opacity animation ✅ (but uses `Easing.bezier(0.4, 0, 0.2, 1)` from old M3 motion guidelines; M3 Expressive uses spring-based motion)
- Dismisses on outside press ✅
- Keyboard-aware positioning ✅
- RTL support ✅
- Escape key dismissal on web ✅
- Back handler on Android ✅
- [ ] No item selection state / active item support
- [ ] No grouped layout (gaps between item groups); current workaround uses `Divider` which is not the spec-aligned grouping mechanism for vertical menus
- [ ] No submenu support
- [ ] No badge support on items
- [ ] M3 Expressive vertical menu shape morphing (active container shape animates as focus moves to submenu) not implemented

### Notes

- The current component implements the baseline menu variant only. The M3 Expressive vertical menu is a largely new feature surface (new shapes, selection states, vibrant color scheme, submenu motion, grouped layout) that requires significant additions.
- The `borderRadius: theme.roundness` bug is a significant visual regression vs spec – the container should be visibly rounded.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.