Skip to content

Commit fca94a9

Browse files
committed
docs(cdk/dialog): add docs and live examples
Adds the documentation and live examples for the new CDK dialog.
1 parent 900ab63 commit fca94a9

16 files changed

+452
-1
lines changed

src/cdk/dialog/dialog.md

+189-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,189 @@
1-
<!-- TODO -->
1+
The `Dialog` service can be used to open unstyled modal dialogs and to build your own dialog
2+
services.
3+
4+
<!-- example(cdk-dialog-overview) -->
5+
6+
You can open a dialog by calling the `open` method either with a component or with a `TemplateRef`
7+
representing the dialog content. The method additionally accepts an optional configuration object.
8+
The `open` method returns a `DialogRef` instance:
9+
10+
```ts
11+
const dialogRef = dialog.open(UserProfileComponent, {
12+
height: '400px',
13+
width: '600px',
14+
panelClass: 'my-dialog',
15+
});
16+
```
17+
18+
The `DialogRef` provides a reference to the opened dialog. You can use the `DialogRef` to close the
19+
dialog, subscribe to dialog events, and modify dialog state. All `Observable` instances on the
20+
`DialogRef` complete when the dialog closes.
21+
22+
```ts
23+
dialogRef.closed.subscribe(result => {
24+
console.log(`Dialog result: ${result}`); // Pizza!
25+
});
26+
27+
dialogRef.close('Pizza!');
28+
```
29+
30+
Components created via `Dialog` can _inject_ `DialogRef` and use it to close the dialog
31+
in which they are contained. When closing, an optional result value can be provided. This result
32+
value is forwarded as the result of the `closed` Observable.
33+
34+
```ts
35+
@Component({/* ... */})
36+
export class YourDialog {
37+
constructor(public dialogRef: DialogRef<string>) {}
38+
39+
closeDialog() {
40+
this.dialogRef.close('Pizza!');
41+
}
42+
}
43+
```
44+
45+
### Dialog styling
46+
47+
The `Dialog` service includes an intentionally limited set of structural styles. You can customize
48+
the dialog's appearance using one of the following approaches.
49+
50+
#### `panelClass` option
51+
The `panelClass` property of `DialogConfig` allows you to apply one or more CSS classes to the
52+
overlay element that contains the custom dialog content. Any styles targeting these CSS classes
53+
must be global styles.
54+
55+
#### Styling the dialog component
56+
You can use the `styles` or `styleUrls` of a custom component to style the dialog content:
57+
58+
```ts
59+
// MyDialog is rendered via `dialog.open(MyDialog)`
60+
@Component({
61+
selector: 'my-dialog',
62+
styles: [`
63+
:host {
64+
display: block;
65+
background: #fff;
66+
border-radius: 8px;
67+
padding: 16px;
68+
}
69+
`]
70+
})
71+
class MyDialog {}
72+
```
73+
74+
<!-- example(cdk-dialog-styling) -->
75+
76+
#### Providing a custom dialog contaier
77+
If you want more control over the dialog's behavior and styling, you can provide your own dialog
78+
container component using the `container` option in `DialogConfig`. This approach requires more
79+
code up-front, but it allows you to customize the DOM structure and behavior of the container
80+
around the dialog content. Custom container components can optionally extend `CdkDialogContainer`
81+
to inherit standard behaviors, such as accessible focus management.
82+
83+
```ts
84+
import {CdkDialogContainer} from '@angular/cdk/dialog';
85+
86+
@Component({
87+
selector: 'my-dialog-container',
88+
styles: [`
89+
:host {
90+
display: block;
91+
background: #fff;
92+
border-radius: 8px;
93+
padding: 16px;
94+
}
95+
`]
96+
})
97+
class MyDialogContainer extends CdkDialogContainer {}
98+
```
99+
100+
### Specifying global configuration defaults
101+
Default dialog options can be specified by providing an instance of `DialogConfig` for
102+
`DEFAULT_DIALOG_CONFIG` in your application's root module.
103+
104+
```ts
105+
@NgModule({
106+
providers: [
107+
{provide: DEFAULT_DIALOG_CONFIG, useValue: {hasBackdrop: false}}
108+
]
109+
})
110+
```
111+
112+
### Sharing data with the Dialog component.
113+
You can use the `data` option to pass information to the dialog component.
114+
115+
```ts
116+
const dialogRef = dialog.open(YourDialog, {
117+
data: {name: 'frodo'},
118+
});
119+
```
120+
121+
Access the data in your dialog component with the `DIALOG_DATA` injection token:
122+
123+
```ts
124+
import {Component, Inject} from '@angular/core';
125+
import {DIALOG_DATA} from '@angular/cdk/dialog';
126+
127+
@Component({
128+
selector: 'your-dialog',
129+
template: 'passed in {{ data.name }}',
130+
})
131+
export class YourDialog {
132+
constructor(@Inject(DIALOG_DATA) public data: {name: string}) { }
133+
}
134+
```
135+
136+
If you're using a `TemplateRef` for your dialog content, the data is available in the template:
137+
138+
```html
139+
<ng-template let-data>
140+
Hello, {{data.name}}
141+
</ng-template>
142+
```
143+
144+
<!-- example(cdk-dialog-data) -->
145+
146+
### Accessibility
147+
148+
`Dialog` creates modal dialogs that implement the ARIA `role="dialog"` pattern by default.
149+
You can change the dialog's role to `alertdialog` via the `DialogConfig`.
150+
151+
You should provide an accessible label to this root dialog element by setting the `ariaLabel` or
152+
`ariaLabelledBy` properties of `DialogConfig`. You can additionally specify a description element
153+
ID via the `ariaDescribedBy` property of `DialogConfig`.
154+
155+
#### Keyboard interaction
156+
157+
By default, the escape key closes `Dialog`. While you can disable this behavior via the
158+
`disableClose` property of `DialogConfig`, doing this breaks the expected interaction pattern
159+
for the ARIA `role="dialog"` pattern.
160+
161+
#### Focus management
162+
163+
When opened, `Dialog` traps browser focus such that it cannot escape the root
164+
`role="dialog"` element. By default, the first tabbable element in the dialog receives focus.
165+
You can customize which element receives focus with the `autoFocus` property of
166+
`DialogConfig`, which supports the following values.
167+
168+
| Value | Behavior |
169+
|------------------|--------------------------------------------------------------------------|
170+
| `first-tabbable` | Focus the first tabbable element. This is the default setting. |
171+
| `first-header` | Focus the first header element (`role="heading"`, `h1` through `h6`) |
172+
| `dialog` | Focus the root `role="dialog"` element. |
173+
| Any CSS selector | Focus the first element matching the given selector. |
174+
175+
While the default setting applies the best behavior for most applications, special cases may benefit
176+
from these alternatives. Always test your application to verify the behavior that works best for
177+
your users.
178+
179+
#### Focus restoration
180+
181+
When closed, `Dialog` restores focus to the element that previously held focus when the
182+
dialog opened by default. You can customize the focus restoration behavior using the `restoreFocus`
183+
property of `DialogConfig`. It supports the following values.
184+
185+
| Value type | Behavior |
186+
|------------------|------------------------------------------------------------------------------------------------------------------|
187+
| `boolean` | When `true`, focus will be restored to the previously-focused element, otherwise focus won't be restored at all. |
188+
| `string` | Value is treated as a CSS selector. Focus will be restored to the element matching the selector. |
189+
| `HTMLElement` | Specific element that focus should be restored to. |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
load("//tools:defaults.bzl", "ng_module")
2+
3+
package(default_visibility = ["//visibility:public"])
4+
5+
ng_module(
6+
name = "dialog",
7+
srcs = glob(
8+
["**/*.ts"],
9+
exclude = ["**/*.spec.ts"],
10+
),
11+
assets = glob([
12+
"**/*.html",
13+
"**/*.css",
14+
]),
15+
deps = [
16+
"//src/cdk/dialog",
17+
"@npm//@angular/forms",
18+
"@npm//@angular/platform-browser",
19+
"@npm//@angular/platform-browser-dynamic",
20+
],
21+
)
22+
23+
filegroup(
24+
name = "source-files",
25+
srcs = glob([
26+
"**/*.html",
27+
"**/*.css",
28+
"**/*.ts",
29+
]),
30+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
:host {
2+
display: block;
3+
background: #fff;
4+
border-radius: 8px;
5+
padding: 8px 16px;
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<h1>Favorite Animal</h1>
2+
<div>
3+
My favorite animal is:
4+
<ul>
5+
<li>
6+
<span *ngIf="data.animal === 'panda'">&#10003;</span> Panda
7+
</li>
8+
<li>
9+
<span *ngIf="data.animal === 'unicorn'">&#10003;</span> Unicorn
10+
</li>
11+
<li>
12+
<span *ngIf="data.animal === 'lion'">&#10003;</span> Lion
13+
</li>
14+
</ul>
15+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<button (click)="openDialog()">Open dialog</button>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import {Component, Inject} from '@angular/core';
2+
import {Dialog, DIALOG_DATA} from '@angular/cdk/dialog';
3+
4+
export interface DialogData {
5+
animal: 'panda' | 'unicorn' | 'lion';
6+
}
7+
8+
/**
9+
* @title Injecting data when opening a dialog
10+
*/
11+
@Component({
12+
selector: 'cdk-dialog-data-example',
13+
templateUrl: 'cdk-dialog-data-example.html',
14+
})
15+
export class CdkDialogDataExample {
16+
constructor(public dialog: Dialog) {}
17+
18+
openDialog() {
19+
this.dialog.open(CdkDialogDataExampleDialog, {
20+
minWidth: '300px',
21+
data: {
22+
animal: 'panda',
23+
},
24+
});
25+
}
26+
}
27+
28+
@Component({
29+
selector: 'cdk-dialog-data-example-dialog',
30+
templateUrl: 'cdk-dialog-data-example-dialog.html',
31+
styleUrls: ['./cdk-dialog-data-example-dialog.css'],
32+
})
33+
export class CdkDialogDataExampleDialog {
34+
constructor(@Inject(DIALOG_DATA) public data: DialogData) {}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
:host {
2+
display: block;
3+
background: #fff;
4+
border-radius: 8px;
5+
padding: 8px 16px 16px;
6+
}
7+
8+
input {
9+
margin: 8px 0;
10+
}
11+
12+
button + button {
13+
margin-left: 8px;
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<h1>Hi {{data.name}}</h1>
2+
<div>
3+
<label id="favorite-animal">What's your favorite animal?</label>
4+
<input for="favorite-animal" [(ngModel)]="data.animal" placeholder="Enter your name">
5+
</div>
6+
<div>
7+
<button (click)="dialogRef.close(data.animal)">OK</button>
8+
<button (click)="dialogRef.close()">Cancel</button>
9+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<ol>
2+
<li>
3+
<label id="dialog-user-name">What's your name?</label>
4+
<input for="dialog-user-name" [(ngModel)]="name">
5+
</li>
6+
<li>
7+
<button (click)="openDialog()">Pick one</button>
8+
</li>
9+
<li *ngIf="animal">
10+
You chose: <i>{{animal}}</i>
11+
</li>
12+
</ol>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import {Component, Inject} from '@angular/core';
2+
import {Dialog, DialogRef, DIALOG_DATA} from '@angular/cdk/dialog';
3+
4+
export interface DialogData {
5+
animal: string;
6+
name: string;
7+
}
8+
9+
/**
10+
* @title CDK Dialog Overview
11+
*/
12+
@Component({
13+
selector: 'cdk-dialog-overview-example',
14+
templateUrl: 'cdk-dialog-overview-example.html',
15+
})
16+
export class CdkDialogOverviewExample {
17+
animal: string | undefined;
18+
name: string;
19+
20+
constructor(public dialog: Dialog) {}
21+
22+
openDialog(): void {
23+
const dialogRef = this.dialog.open<string>(CdkDialogOverviewExampleDialog, {
24+
width: '250px',
25+
data: {name: this.name, animal: this.animal},
26+
});
27+
28+
dialogRef.closed.subscribe(result => {
29+
console.log('The dialog was closed');
30+
this.animal = result;
31+
});
32+
}
33+
}
34+
35+
@Component({
36+
selector: 'cdk-dialog-overview-example-dialog',
37+
templateUrl: 'cdk-dialog-overview-example-dialog.html',
38+
styleUrls: ['cdk-dialog-overview-example-dialog.css'],
39+
})
40+
export class CdkDialogOverviewExampleDialog {
41+
constructor(public dialogRef: DialogRef<string>, @Inject(DIALOG_DATA) public data: DialogData) {}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
:host {
2+
display: block;
3+
background: #fff;
4+
border-radius: 8px;
5+
padding: 16px;
6+
max-width: 500px;
7+
animation: custom-dialog-enter 1s ease;
8+
}
9+
10+
@keyframes custom-dialog-enter {
11+
from {
12+
transform: scale(0) rotate(360deg);
13+
}
14+
15+
to {
16+
transform: none;
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Did you ever hear the tragedy of Darth Plagueis The Wise? I thought not. It's not a story the Jedi
2+
would tell you. It's a Sith legend. Darth Plagueis was a Dark Lord of the Sith, so powerful and so
3+
wise he could use the Force to influence the midichlorians to create life… He had such a knowledge
4+
of the dark side that he could even keep the ones he cared about from dying. The dark side of the
5+
Force is a pathway to many abilities some consider to be unnatural. He became so powerful… the only
6+
thing he was afraid of was losing his power, which eventually, of course, he did. Unfortunately,
7+
he taught his apprentice everything he knew, then his apprentice killed him in his sleep. Ironic.
8+
He could save others from death, but not himself.
9+
10+
<hr>
11+
12+
<button (click)="dialogRef.close()">Close</button>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<button (click)="openDialog()">Open custom dialog</button>

0 commit comments

Comments
 (0)