feat(aria/menu): Add possibility to create a shared menu component from aria/menu
- Dominant language
- TypeScript
- Stars
- 25k
- Forks
- 6.8k
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 91
Description
### Feature Description
When building a menu using [aria/menu](https://angular.dev/guide/aria/menu#menu-with-trigger) you have to have the following structure:
1. an for cdkConnectedOverlay
2. a container element with ngMenu
3. another for ngMenuContent
4. only then the actual ngMenuItem elements
This results in 4 structural levels that need to be repeated every time you need a new menu.
I attempted to create a shared menu component (similar to Angular Material’s MatMenu) in order to reduce this complexity to 2 levels and enable an API like:
```
Open Menu
mark_email_read
Mark as read
snooze
Snooze
```
Internally, app-menu wraps Menu and MenuContent:
```
@Component({
selector: 'app-menu',
imports: [OverlayModule, Menu, MenuContent],
template: `
`
})
export class AppMenu {
appMenuTrigger = input.required();
formatMenu = viewChild>('formatMenu');
overlayPositions: ConnectedPosition[] = [{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}];
}
```
and menu items are wrapped like this:
```
@Component({
selector: 'app-menu-item',
template: '',
hostDirectives: [{ directive: MenuItem, inputs: ['value: value'] }]
})
export class AppMenuItem {}
```
**Problem**
With this approach, accessibility breaks (keyboard navigation no longer works correctly). This seems to happen because `Menu` cannot properly register `MenuItem` children when they are content projected.
**Proposed enhancement**
Expose a public API on `Menu` that allows the menu to "refresh" in order to register the items when they are content projected.
### Use Case
_No response_
Contributor guide
Assessment
This issue has not been assessed yet.