Skip to content

Commit f26382f

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

File tree

2 files changed

+222
-0
lines changed

2 files changed

+222
-0
lines changed

src/cdk-experimental/menu/menu.md

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
The `@angular/cdk-experimental/menu` module provides directives to help create custom menu
2+
interactions based on the [WAI ARIA specification][aria].
3+
4+
By using `@angular/cdk-experimental/menu` you get all of the expected behaviors following the ARIA
5+
best practices including consideration for left-to-right and right-to-left layouts, and accessible
6+
interaction. Further, all directives apply their associated ARIA roles to the component they are
7+
added to.
8+
9+
### Supported ARIA Roles
10+
11+
The directives in `@angular/cdk-experimental/menu` set the appropriate roles on their host element.
12+
13+
| Directive | ARIA Role |
14+
| ------------------- | ---------------- |
15+
| CdkMenuBar | menubar |
16+
| CdkMenu | menu |
17+
| CdkMenuGroup | group |
18+
| CdkMenuItem | menuitem |
19+
| CdkMenuItemRadio | menuitemradio |
20+
| CdkMenuItemCheckbox | menuitemcheckbox |
21+
22+
### Getting started
23+
24+
Import the `CdkMenuModule` into the `NgModule` in which you want to create menus. You can then apply
25+
menu directives to build your custom menu. A typical menu consists of the following directives:
26+
27+
- `cdkMenuTriggerFor` - links a trigger button to a menu you intend to open
28+
- `cdkMenuPanel` - wraps the menu and provides a link between the `cdkMenuTriggerFor` and the
29+
`cdkMenu`
30+
- `cdkMenu` - the actual menu you want to open
31+
- `cdkMenuItem` - added to each button
32+
33+
<!-- TODO basic standalone menu example (like mat-menu has) -->
34+
35+
Most menu interactions consist of two parts: a trigger and a menu panel.
36+
37+
#### Triggers
38+
39+
You must add the `cdkMenuItem` and `cdkMenuTriggerFor` directives to triggers like so,
40+
41+
```html
42+
<button cdkMenuItem [cdkMenuTriggerFor]="menu">Click me!</button>
43+
```
44+
45+
Adding `cdkMenuItem` gives you keyboard navigation and focus management. Associating a trigger with
46+
a menu is done through the `cdkMenuTriggerFor` directive and you must provide a template reference
47+
variable to it. Once both of these directives are set, you can toggle the associated menu
48+
programmatically, using a mouse or using a keyboard.
49+
50+
#### Menu panels
51+
52+
You must wrap pop-up menus with an `ng-template` with the `cdkMenuPanel` directive and a reference
53+
variable which must be of type `cdkMenuPanel`. Further, the `cdkMenu` must also reference the
54+
`cdkMenuPanel`.
55+
56+
```html
57+
<ng-template cdkMenuPanel #panel="cdkMenuPanel">
58+
<div cdkMenu [cdkMenuPanel]="panel">
59+
<!-- some content -->
60+
</div>
61+
</ng-template>
62+
```
63+
64+
Note that Angular CDK provides no styles; you must add styles as part of building your custom menu.
65+
66+
### Menu Bars
67+
68+
The `CdkMenuBar` directive follows the [ARIA menubar][menubar] spec and behaves similar to a desktop
69+
app menubar. It consists of at least one `CdkMenuItem` which triggers a submenu. A menubar can be
70+
layed out horizontally or vertically (defaulting to horizontal). If the style is changed, you must
71+
set the `orientation` attribute to match in order for the keyboard navigation to work properly and
72+
for menus to open up in the correct location.
73+
74+
The primary difference between a menubar and a standalone menu is the menubar groups together the
75+
triggering components. Therefore, menus in a menubar can be opened/closed when hovering between
76+
their triggers and keyboard navigation listens to left and right arrow buttons which toggles between
77+
the menu items in the menubar.
78+
79+
<!-- TODO basic menubar example (google docs?) -->
80+
81+
### Context Menus
82+
83+
A context menu opens when a user right-clicks within some container element. A context is an area of
84+
your application which contains some content where you want to open up a menu. When a user
85+
right-clicks within the context the associated menu opens up next to their cursor - as you would
86+
expect with a typical right click menu.
87+
88+
<!-- TODO basic context menu example -->
89+
90+
Nested container elements can have context menu triggers at each level. When a user right-clicks,
91+
the menu associated with the closest container element opens.
92+
93+
```html
94+
<div [cdkContextMenuTriggerFor]="outer">
95+
My outer context
96+
<div [cdkContextMenuTriggerFor]="inner">My inner context</div>
97+
</div>
98+
```
99+
100+
In the example above, right clicking on "My inner context" will open up the "inner" menu and right
101+
clicking inside "My outer context" will open up the "outer" menu.
102+
103+
### Inline Menus
104+
105+
An _inline menu_ is a menu that lives directly on the page rather than a pop-up associated with a
106+
trigger. You can use an inline menu when you want a persistent menu interaction on a page. Menu
107+
items within an inline menus are logically grouped together and you can navigate through them using
108+
your keyboard.
109+
110+
<!-- TODO inline menu example (gmail buttons?) -->
111+
112+
### Menu Items
113+
114+
Both menu and menubar elements should exclusively contain menuitem elements. This directive allows
115+
the items to be navigated to via keyboard interaction.
116+
117+
A menuitem by itself can provide some user defined action by hooking into the `cdkMenuItemTriggered`
118+
output. An example may be a close button which performs some closing logic.
119+
120+
```html
121+
<ng-template cdkMenuPanel #panel="cdkMenuPanel">
122+
<div cdkMenu [cdkMenuPanel]="panel">
123+
<button cdkMenuItem (cdkMenuItemTriggered)="closeApp()">Close</button>
124+
</div>
125+
</ng-template>
126+
```
127+
128+
You can create nested menus by using a menuitem as the trigger for another menu.
129+
130+
```html
131+
<ng-template cdkMenuPanel #panel="cdkMenuPanel">
132+
<div cdkMenu [cdkMenuPanel]="panel">
133+
<button cdkMenuItem [cdkMenuTriggerFor]="submenu">Open Submenu</button>
134+
</div>
135+
</ng-template>
136+
```
137+
138+
A menuitem also has two sub-types, neither of which should trigger a menu: CdkMenuItemCheckbox and
139+
CdkMenuItemRadio
140+
141+
#### Menu Item Checkboxes
142+
143+
A `cdkMenuItemCheckbox` is a special type of menuitem that behaves as a checkbox. You can use this
144+
type of menuitem to toggle items on and off. A component with the `cdkMenuItemCheckbox` directive
145+
does not need the additional `cdkMenuItem` directive.
146+
147+
#### Menu Item Radios
148+
149+
A `cdkMenuItemRadio` is a special type of menuitem that behaves as a radio button. You can use this
150+
type of menuitem for menus with exclusively selectable items. A component with the
151+
`cdkMenuItemRadio` directive does not need the additional `cdkMenuItem` directive.
152+
153+
#### Groups
154+
155+
By default `cdkMenu` acts as a group for `cdkMenuItemRadio` elements. Elements with
156+
`cdkMenuItemRadio` added as children of a `cdkMenu` will be logically grouped and only a single item
157+
can have the checked state.
158+
159+
If you would like to have unrelated groups of radio buttons within a single menu you should use the
160+
`cdkMenuGroup` directive.
161+
162+
```html
163+
<ng-template cdkMenuPanel #panel="cdkMenuPanel">
164+
<div cdkMenu [cdkMenuPanel]="panel">
165+
<!-- Font size -->
166+
<div cdkMenuGroup>
167+
<button cdkMenuItemRadio>Small</button>
168+
<button cdkMenuItemRadio>Medium</button>
169+
<button cdkMenuItemRadio>Large</button>
170+
</div>
171+
<hr />
172+
<!-- Paragraph alignment -->
173+
<div cdkMenuGroup>
174+
<button cdkMenuItemRadio>Left</button>
175+
<button cdkMenuItemRadio>Center</button>
176+
<button cdkMenuItemRadio>Right</button>
177+
</div>
178+
</div>
179+
</ng-template>
180+
```
181+
182+
Note however that when the menu is closed and reopened any state is lost. You must subscribe to the
183+
groups `change` output, or to `cdkMenuItemToggled` on each radio item and track changes your self.
184+
Finally, you can provide state for each item using the `checked` attribute.
185+
186+
<!-- TODO standalone menu example with checkboxes and grouped radios -->
187+
188+
### Smart Menu Aim
189+
190+
`@angular/cdk-experimental/menu` intelligently predicts when a user intends to navigate to an open
191+
submenu and prevent premature closeouts. This functionality prevents users from having to hunt
192+
through the open menus in a maze-like fashion to reach their destination.
193+
194+
![menu aim diagram][diagram]
195+
196+
As demonstrated in the diagram above we first track the user's mouse movements within a menu. Next,
197+
when a user mouses into a sibling menu item (e.g. Share button) the sibling item asks the Menu Aim
198+
service if it can perform its close actions. In order to determine if the current submenu can be
199+
closed out, the Menu Aim service calculates the slope between a selected target coordinate in the
200+
submenu and the previous mouse point, and the slope between the target and the current mouse point.
201+
If the slope of the current mouse point is greater than the slope of the previous that means the
202+
user is moving towards the submenu and we shouldn't close out. Users however may sometimes stop
203+
short in a sibling item after moving towards the submenu. The service is intelligent enough the
204+
detect this intention and will trigger the next menu.
205+
206+
### Accessibility
207+
208+
The set of directives defined in `@angular/cdk-experimental/menu` follow accessability best
209+
practices as defined in the [ARIA spec][menubar]. Specifically, the menus are aware of left-to-right
210+
and right-to-left layouts and opened appropriately. You should however add any necessary CSS styles.
211+
Menu items should always have meaningful labels, whether through text content, `aria-label`, or
212+
`aria-labelledby` Finally, keyboard interaction is supported as defined in the [ARIA menubar
213+
keyboard interaction spec][keyboard].
214+
215+
<!-- links -->
216+
217+
[aria]: https://www.w3.org/TR/wai-aria-1.1/ 'ARIA Spec'
218+
[menubar]: https://www.w3.org/TR/wai-aria-practices-1.1/#menu 'ARIA Menubar Pattern'
219+
[keyboard]:
220+
https://www.w3.org/TR/wai-aria-practices-1.1/#keyboard-interaction-12
221+
'ARIA Menubar Keyboard Interaction'
222+
[diagram]: menuaim.png 'Menu Aim Diagram'

src/cdk-experimental/menu/menuaim.png

62.6 KB
Loading

0 commit comments

Comments
 (0)