Skip to content

Commit ee003ef

Browse files
committed
docs(cdk-experimental/menu): add initial documentation for cdk menu directives
1 parent fe14d88 commit ee003ef

File tree

1 file changed

+167
-0
lines changed

1 file changed

+167
-0
lines changed

src/cdk-experimental/menu/menu.md

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
The `@angular/cdk-experimental/menu` module provides you with a way to easily create complex menu interfaces with support for:
2+
3+
- Standalone Menus
4+
- Menubars
5+
- Context Menus
6+
- Inline Menus
7+
- MenuItems
8+
- RadioButtonItems
9+
- CheckboxItems
10+
11+
`@angular/cdk-experimental/menu` can also intelligently predict if a user is attempting to navigate to an open submenu and prevent premature closeouts.
12+
13+
By using `@angular/cdk-experimental/menu` you get all of the expected behaviors following aria best practices including consideration for left-to-right and right-to-left layouts, and accessible interaction. Further, all directives apply their associated aria roles to the component they are added to.
14+
15+
### Getting started
16+
17+
Start by importing the `CdkMenuModule` into the `NgModule` where you want to create menus. You can now add the various directives in order to build out your menu. A basic standalone menu consists of the following directives:
18+
19+
- `cdkMenuItem` - added to the button itself
20+
- `cdkMenuTriggerFor` - links a trigger button to a menu you intend to open
21+
- `cdkMenuPanel` - wraps the menu and provides a link between the `cdkMenuTriggerFor` and the `cdkMenu`
22+
- `cdkMenu` - the actual menu you want to open
23+
24+
<!-- TODO basic standalone menu example (like mat-menu has) -->
25+
26+
Keep in mind that there are two important requirements which must be kept in mind when building menus:
27+
28+
First, a triggering component, or a component inside of a `CdkMenu` or `CdkMenuBar`, must have the `cdkMenuItem` directive like so,
29+
30+
```html
31+
<button cdkMenuItem [cdkMenuTriggerFor]="menu">Click me!</button>
32+
```
33+
34+
```html
35+
<div cdkMenu>
36+
<button cdkMenuItem>Click me!</button>
37+
</div>
38+
```
39+
40+
Adding `cdkMenuItem` allows for keyboard navigation and focus management.
41+
42+
Second, non-inline menus must be wrapped in an `ng-template` which must have a directive of `cdkMenuPanel` and a reference variable must be of type `cdkMenuPanel`. Further, the `cdkMenu` must also reference the `cdkMenuPanel`.
43+
44+
```html
45+
<ng-template cdkMenuPanel #panel="cdkMenuPanel">
46+
<div cdkMenu [cdkMenuPanel]="panel">
47+
<!-- some content -->
48+
</div>
49+
</ng-template>
50+
```
51+
52+
Finally, note that this is part of the cdk and there is no styling - it is up to you to provide styles. It is also important that your style matches the `orientation` attribute on both the `cdkMenu` and `cdkMenuBar` directives.
53+
54+
### Standalone Menus
55+
56+
A standalone menu is triggered from a single standalone button and standalone menu triggers cannot be grouped together meaning each single trigger is a tabstop. Standalone triggers can be opened from the keyboard and the opened menu behaves just like it does in the other implementations.
57+
58+
<!-- TODO standalone trigger example (use from above?) -->
59+
60+
### MenuBars
61+
62+
The `CdkMenuBar` directive follows the [aria menubar][1] spec and operates similar to a desktop app menubar. It consists of at least one `CdkMenuItem` which triggers a submenu. A menubar can be layed out horizontally or vertically (defaulting to horizontal). If the style is changed, the `orientation` attribute must be set to match in order for the keyboard navigation to work properly and for menus to open up in the correct location.
63+
64+
The primary difference between a menubar and a standalone menu is the menubar groups together the triggering components. Therefore, menus in a menubar can be opened/closed when hovering between their triggers and keyboard navigation listens to left and right arrow buttons which toggles between the menu items in the menubar.
65+
66+
<!-- TODO basic menubar example (google docs?) -->
67+
68+
### Context Menus
69+
70+
A context menu is a menu which opens on a right click which occurs within some context component. A context is an area of your application which contains some content where you want to open up a menu. When a user right-clicks within the context the associated menu opens up next to their cursor - as you would expect with a typical right click menu.
71+
72+
<!-- TODO basic context menu example -->
73+
74+
Context menu triggers may be nested within parent contexts and when a user right clicks, the deepest context menu in which the user is hovering in is opened up.
75+
76+
```html
77+
<div [cdkContextMenuTriggerFor]="outer">
78+
My outer context
79+
<div [cdkContextMenuTriggerFor]="inner">
80+
My inner context
81+
</div>
82+
</div>
83+
```
84+
85+
In the example above, right clicking on "My inner context" will open up the "inner" menu and right clicking inside "My outer context" will open up the "outer" menu.
86+
87+
### Inline Menus
88+
89+
Inline menus are groups of menu items which typically do not trigger their own menus and the menu items implement some type of on-click behavior. The benefit of using an inline menu over a group of standalone menu items is that inline menus provide keyboard navigation and focus management. Menu items within an inline menus are logically grouped together.
90+
91+
<!-- TODO inline menu example (gmail buttons?) -->
92+
93+
### Menuitem
94+
95+
Components which interact with or are placed inside of a menu or menubar should typically have the `cdkMenuItem` directive provided. This directive allows the items to be navigated to via keyboard interaction.
96+
97+
A menuitem by itself can provide some user defined action by hooking into the `cdkMenuItemTriggered` output. An example may be a close button which performs some closing logic.
98+
99+
```html
100+
<ng-template cdkMenuPanel #panel="cdkMenuPanel">
101+
<div cdkMenu [cdkMenuPanel]="panel">
102+
<button cdkMenuItem [cdkMenuItemTriggered]="closeApp()">Close</button>
103+
</div>
104+
</ng-template>
105+
```
106+
107+
`cdkMenuItem` should also be added to a component which triggers a menu or submenu.
108+
109+
```html
110+
<ng-template cdkMenuPanel #panel="cdkMenuPanel">
111+
<div cdkMenu [cdkMenuPanel]="panel">
112+
<button cdkMenuItem [cdkMenuTriggerFor]="submenu">Open Submenu</button>
113+
</div>
114+
</ng-template>
115+
```
116+
117+
A menuitem also has two sub-types, neither of which should trigger a menu:
118+
119+
- CdkMenuItemCheckbox
120+
- CdkMenuItemRadio
121+
122+
#### Menuitemcheckbox
123+
124+
A component with the `cdkMenuItemCheckbox` directive behaves just as you would expect a typical checkbox to behave. A use case may be toggling an independent setting since it contains a checked state. A component with the `cdkMenuItemCheckbox` directive does not need the additional `cdkMenuItem` directive.
125+
126+
#### Menuitemradio
127+
128+
A `cdkMenuItemRadio` behaves as you would expect a radio button to behave. A use case may be toggling through more than one state since radio buttons can be grouped together. A component with the `cdkMenuItemRadio` directive does not need the additional `cdkMenuItem` directive.
129+
130+
#### Groups
131+
132+
By default `cdkMenu` acts as a group for `cdkMenuItemRadio` elements. That is, components marked with `cdkMenuItemRadio` added as children of a `cdkMenu` will be logically grouped and only a single component can have the checked state.
133+
134+
If you would like to have unrelated groups of radio buttons within a single menu you should use the `cdkMenuGroup` directive.
135+
136+
```html
137+
<ng-template cdkMenuPanel #panel="cdkMenuPanel">
138+
<div cdkMenu [cdkMenuPanel]="panel">
139+
<!-- Font size -->
140+
<div cdkMenuGroup>
141+
<button cdkMenuItemRadio>Small</button>
142+
<button cdkMenuItemRadio>Medium</button>
143+
<button cdkMenuItemRadio>Large</button>
144+
</div>
145+
<hr />
146+
<!-- Paragraph alignment -->
147+
<div cdkMenuGroup>
148+
<button cdkMenuItemRadio>Left</button>
149+
<button cdkMenuItemRadio>Center</button>
150+
<button cdkMenuItemRadio>Right</button>
151+
</div>
152+
</div>
153+
</ng-template>
154+
```
155+
156+
Note however that when the menu is closed and reopened any state is lost. You must subscribe to the groups `change` output, or to `cdkMenuItemToggled` on each radio item and track changes your self.
157+
158+
<!-- TODO standalone menu example with checkboxes and grouped radios -->
159+
160+
### Accessability
161+
162+
The set of directives defined in `@angular/cdk-experimental/menu` follow accessability best practices as defined in the [aria spec][1]. Specifically, the menus are aware of left-to-right and right-to-left layouts and opened appropriately however it is up to you to handle any related styling. Further, screen readers are supported however you should add `aria-label` or `aria-labelledby` if menu items do not have text. Finally, keyboard interaction is supported as defined in the [aria menubar keyboard interaction spec][2].
163+
164+
<!-- links -->
165+
166+
[1]: https://www.w3.org/TR/wai-aria-practices-1.1/#menu 'Aria Menubar Pattern'
167+
[2]: https://www.w3.org/TR/wai-aria-practices-1.1/#keyboard-interaction-12 'Aria Menubar Keyboard Interaction'

0 commit comments

Comments
 (0)