@workday/canvas-kit-docs 16.0.10 → 16.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es6/lib/stackblitzFiles/packageJSONFile.js +5 -5
- package/dist/es6/lib/stackblitzFiles/packageJSONFile.ts +5 -5
- package/dist/mdx/preview-react/status-indicator/StatusIndicator.mdx +119 -6
- package/dist/mdx/preview-react/status-indicator/examples/Icon.tsx +2 -2
- package/dist/mdx/react/dialog/Dialog.mdx +235 -48
- package/dist/mdx/react/form-field/FormField.mdx +174 -45
- package/dist/mdx/react/menu/Menu.mdx +188 -43
- package/dist/mdx/react/modal/Modal.mdx +230 -52
- package/dist/mdx/react/popup/Popup.mdx +297 -11
- package/dist/mdx/react/text-area/TextArea.mdx +134 -30
- package/dist/mdx/react/text-input/TextInput.mdx +193 -34
- package/package.json +6 -6
|
@@ -18,11 +18,11 @@ export const packageJSONFile = `{
|
|
|
18
18
|
"@emotion/react": "11.11.4",
|
|
19
19
|
"@types/react": "18.2.60",
|
|
20
20
|
"@types/react-dom": "18.2.19",
|
|
21
|
-
"@workday/canvas-kit-labs-react": "16.0.
|
|
22
|
-
"@workday/canvas-kit-preview-react": "16.0.
|
|
23
|
-
"@workday/canvas-kit-react": "16.0.
|
|
24
|
-
"@workday/canvas-kit-react-fonts": "^16.0.
|
|
25
|
-
"@workday/canvas-kit-styling": "16.0.
|
|
21
|
+
"@workday/canvas-kit-labs-react": "16.0.12",
|
|
22
|
+
"@workday/canvas-kit-preview-react": "16.0.12",
|
|
23
|
+
"@workday/canvas-kit-react": "16.0.12",
|
|
24
|
+
"@workday/canvas-kit-react-fonts": "^16.0.12",
|
|
25
|
+
"@workday/canvas-kit-styling": "16.0.12",
|
|
26
26
|
"@workday/canvas-system-icons-web": "^5.0.3",
|
|
27
27
|
"@workday/canvas-expressive-icons-web": "1.0.1",
|
|
28
28
|
"@workday/canvas-tokens-web": "4.4.0-beta.11"
|
|
@@ -19,11 +19,11 @@ export const packageJSONFile = `{
|
|
|
19
19
|
"@emotion/react": "11.11.4",
|
|
20
20
|
"@types/react": "18.2.60",
|
|
21
21
|
"@types/react-dom": "18.2.19",
|
|
22
|
-
"@workday/canvas-kit-labs-react": "16.0.
|
|
23
|
-
"@workday/canvas-kit-preview-react": "16.0.
|
|
24
|
-
"@workday/canvas-kit-react": "16.0.
|
|
25
|
-
"@workday/canvas-kit-react-fonts": "^16.0.
|
|
26
|
-
"@workday/canvas-kit-styling": "16.0.
|
|
22
|
+
"@workday/canvas-kit-labs-react": "16.0.12",
|
|
23
|
+
"@workday/canvas-kit-preview-react": "16.0.12",
|
|
24
|
+
"@workday/canvas-kit-react": "16.0.12",
|
|
25
|
+
"@workday/canvas-kit-react-fonts": "^16.0.12",
|
|
26
|
+
"@workday/canvas-kit-styling": "16.0.12",
|
|
27
27
|
"@workday/canvas-system-icons-web": "^5.0.3",
|
|
28
28
|
"@workday/canvas-expressive-icons-web": "1.0.1",
|
|
29
29
|
"@workday/canvas-tokens-web": "4.4.0-beta.11"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {ExampleCodeBlock, SymbolDoc} from '@workday/canvas-kit-docs';
|
|
2
2
|
|
|
3
3
|
import Basic from './examples/Basic';
|
|
4
4
|
import Custom from './examples/Custom';
|
|
@@ -46,6 +46,10 @@ position of the icon may be adjusted depending on where you place it in the mark
|
|
|
46
46
|
|
|
47
47
|
<ExampleCodeBlock code={Icon} />
|
|
48
48
|
|
|
49
|
+
> **Accessibility Note**: In this example, the icon is used as a decoration and is intentionally
|
|
50
|
+
> hidden from screen readers. If you're using icons to convey additional information, add
|
|
51
|
+
> `role="img"` and a translated `aria-label` string to `StatusIndicator.Icon`.
|
|
52
|
+
|
|
49
53
|
### Overflow
|
|
50
54
|
|
|
51
55
|
We **strongly** discourage using text in a `StatusIndicator` which will cause it to exceed its
|
|
@@ -61,14 +65,16 @@ of `StatusIndicator` via [style props](/get-started/for-developers/documentation
|
|
|
61
65
|
Set the `variant` prop of `StatusIndicator` to adjust its background color. `variant` accepts the
|
|
62
66
|
following values:
|
|
63
67
|
|
|
64
|
-
- `gray`
|
|
65
|
-
- `orange`
|
|
66
|
-
- `blue`
|
|
67
|
-
- `green`
|
|
68
|
-
- `red`
|
|
68
|
+
- `neutral` (default; `gray` is a deprecated alias)
|
|
69
|
+
- `caution` (`orange` is a deprecated alias)
|
|
70
|
+
- `info` (`blue` is a deprecated alias)
|
|
71
|
+
- `positive` (`green` is a deprecated alias)
|
|
72
|
+
- `critical` (`red` is a deprecated alias)
|
|
69
73
|
- `transparent`
|
|
70
74
|
|
|
71
75
|
The background color dictated by the `variant` will be dark or light based on the `emphasis`.
|
|
76
|
+
`variant` and `emphasis` change color only—they do not change the accessible name. Put the status
|
|
77
|
+
meaning in **`StatusIndicator.Label`**.
|
|
72
78
|
|
|
73
79
|
<ExampleCodeBlock code={Variants} />
|
|
74
80
|
|
|
@@ -84,6 +90,113 @@ Status Indicator and its subcomponents support custom styling via the `cs` prop.
|
|
|
84
90
|
information, check our
|
|
85
91
|
["How To Customize Styles"](https://workday.github.io/canvas-kit/?path=/docs/styling-guides-customizing-styles--docs).
|
|
86
92
|
|
|
93
|
+
## Accessibility
|
|
94
|
+
|
|
95
|
+
`StatusIndicator` is a compact, **non-interactive** status label. The accessibility goal is that
|
|
96
|
+
assistive technology users get the same status meaning as sighted users from
|
|
97
|
+
**`StatusIndicator.Label`** text—not from color, emphasis, or a decorative icon.
|
|
98
|
+
|
|
99
|
+
### Minimum Accessible Structure
|
|
100
|
+
|
|
101
|
+
The following matches the [Basic Example](#basic-example): a container and a visible label. Icon is
|
|
102
|
+
optional.
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
import {StatusIndicator} from '@workday/canvas-kit-preview-react/status-indicator';
|
|
106
|
+
|
|
107
|
+
<StatusIndicator>
|
|
108
|
+
<StatusIndicator.Label>Unpublished</StatusIndicator.Label>
|
|
109
|
+
</StatusIndicator>;
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Always include **`StatusIndicator.Label`** with concise text that names the status. Do not rely on
|
|
113
|
+
**`variant`**, **`emphasis`**, or **`StatusIndicator.Icon`** as the only indicator of meaning.
|
|
114
|
+
|
|
115
|
+
### Built-in Behaviors
|
|
116
|
+
|
|
117
|
+
Canvas Kit applies visual layout and color through `statusIndicatorStencil` when you compose
|
|
118
|
+
**`StatusIndicator`**, **`StatusIndicator.Label`**, and optionally **`StatusIndicator.Icon`**. It
|
|
119
|
+
does **not** apply `role="img"` or an accessible name on the icon. **Do not duplicate them** in
|
|
120
|
+
consuming code. Only add icon ARIA when the informative-icon requirement below applies.
|
|
121
|
+
|
|
122
|
+
**ARIA and DOM** (_applied by subcomponents_):
|
|
123
|
+
|
|
124
|
+
- **`StatusIndicator`**: renders a `div` (override with `as` if needed). Default `maxWidth` is
|
|
125
|
+
`200px`. Default `variant` is `neutral`; default `emphasis` is `low`. No ARIA role is set.
|
|
126
|
+
- **`StatusIndicator.Label`**: renders a `span` with bold subtext, `white-space: nowrap`,
|
|
127
|
+
`overflow: hidden`, and `text-overflow: ellipsis`. Truncation is visual; the full text remains in
|
|
128
|
+
the accessibility tree.
|
|
129
|
+
- **`StatusIndicator.Icon`**: renders `SystemIcon` at size `20`. It does **not** set `role="img"` or
|
|
130
|
+
`aria-label`. If `icon.type` is missing, the icon renders nothing.
|
|
131
|
+
|
|
132
|
+
**Keyboard** (_not a control by default_):
|
|
133
|
+
|
|
134
|
+
- **`StatusIndicator`** is not in the tab order. There is no built-in keyboard behavior.
|
|
135
|
+
|
|
136
|
+
**Screen reader expectations** (_when built-in behaviors are used as intended_):
|
|
137
|
+
|
|
138
|
+
- Assistive technology should announce the **`StatusIndicator.Label`** text as the content of the
|
|
139
|
+
indicator
|
|
140
|
+
- `variant` and `emphasis` are **not** announced
|
|
141
|
+
- A decorative **`StatusIndicator.Icon`** (no `role="img"`) should not add a separate accessible
|
|
142
|
+
name
|
|
143
|
+
- [**OverflowTooltip**](https://workday.github.io/canvas-kit/?path=/docs/components-popups-tooltip--docs#tooltips-on-overflowing-content)
|
|
144
|
+
uses `type="muted"` and does not set `aria-label` on the target—the accessible name stays the
|
|
145
|
+
element's text content
|
|
146
|
+
|
|
147
|
+
### Accessibility Requirements
|
|
148
|
+
|
|
149
|
+
Required in application code for an accessible Status Indicator. Rows marked _(conditional)_ apply
|
|
150
|
+
only when the situation matches—otherwise omit.
|
|
151
|
+
|
|
152
|
+
**If no design spec is provided:** include a visible **`StatusIndicator.Label`**; keep the icon
|
|
153
|
+
decorative (omit `role="img"` and `aria-label`); omit `tabIndex` and **`OverflowTooltip`**. Prefer
|
|
154
|
+
short label text so truncation is unnecessary.
|
|
155
|
+
|
|
156
|
+
| Requirement | How to satisfy |
|
|
157
|
+
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
158
|
+
| Visible status text | **`StatusIndicator.Label`** with translated text that names the status (for example, "Unpublished", not color alone) |
|
|
159
|
+
| Color is not the only indicator | Use **`variant`** / **`emphasis`** only as visual reinforcement of the label. See [Failure of Success Criterion 1.4.1 due to identifying required or error fields using color differences only](https://www.w3.org/WAI/WCAG22/Techniques/failures/F81) |
|
|
160
|
+
| Decorative icon _(conditional)_ | **`StatusIndicator.Icon`** with `icon={...}` and **no** `role="img"` when the icon only supports the label visually |
|
|
161
|
+
| Informative icon _(conditional)_ | On **`StatusIndicator.Icon`**, set `role="img"` and a translated `aria-label` that adds meaning **beyond** the label text |
|
|
162
|
+
| Overflowed label _(conditional)_ | Avoid exceeding the `200px` max width. If truncation cannot be avoided, wrap **`StatusIndicator`** in **`OverflowTooltip`** and set `tabIndex={0}` so keyboard and mouse users can reveal the full text. See the [Overflow example](#overflow) |
|
|
163
|
+
|
|
164
|
+
**Informative icon** _(conditional)_:
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
import {StatusIndicator} from '@workday/canvas-kit-preview-react/status-indicator';
|
|
168
|
+
import {cloudArrowUpIcon} from '@workday/canvas-system-icons-web';
|
|
169
|
+
|
|
170
|
+
<StatusIndicator>
|
|
171
|
+
<StatusIndicator.Icon role="img" aria-label="Waiting to sync" icon={cloudArrowUpIcon} />
|
|
172
|
+
<StatusIndicator.Label>Unpublished</StatusIndicator.Label>
|
|
173
|
+
</StatusIndicator>;
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Summary for code generation:**
|
|
177
|
+
|
|
178
|
+
- **REQUIRED:** visible **`StatusIndicator.Label`** whose text conveys the status
|
|
179
|
+
- **CONDITIONAL:** `role="img"` + translated `aria-label` on **`StatusIndicator.Icon`**,
|
|
180
|
+
**`OverflowTooltip`** + `tabIndex={0}`
|
|
181
|
+
|
|
182
|
+
### Anti-Patterns
|
|
183
|
+
|
|
184
|
+
Do **not** generate code that does the following (see **Accessibility Requirements** above for what
|
|
185
|
+
to supply instead):
|
|
186
|
+
|
|
187
|
+
- Omit **`StatusIndicator.Label`** or use an empty label, relying on `variant`, `emphasis`, or an
|
|
188
|
+
icon for meaning
|
|
189
|
+
- Set `role="img"` on a decorative **`StatusIndicator.Icon`**, or set `role="img"` without a
|
|
190
|
+
translated `aria-label`—that can expose an unnamed image to assistive technology. See **Decorative
|
|
191
|
+
icon** and **Informative icon** in **Accessibility Requirements**
|
|
192
|
+
- Duplicate the label text as `aria-label` on the icon when the icon adds no extra meaning
|
|
193
|
+
- Add `role="status"`, `aria-live`, or `aria-label` on **`StatusIndicator`** by default—Canvas Kit
|
|
194
|
+
does not wire these, and they change how assistive technology treats a static label. If a design
|
|
195
|
+
requires announcing asynchronous updates, see
|
|
196
|
+
[ARIA Live Regions](https://workday.github.io/canvas-kit/?path=/docs/guides-accessibility-aria-live-regions--docs)
|
|
197
|
+
- Truncate label text without **`OverflowTooltip`** and `tabIndex={0}` when keyboard users must read
|
|
198
|
+
the overflow
|
|
199
|
+
|
|
87
200
|
## Component API
|
|
88
201
|
|
|
89
202
|
<SymbolDoc name="StatusIndicator" fileName="/preview-react/" />
|
|
@@ -12,12 +12,12 @@ export default () => {
|
|
|
12
12
|
return (
|
|
13
13
|
<Flex cs={parentContainerStyles}>
|
|
14
14
|
<StatusIndicator>
|
|
15
|
-
<StatusIndicator.Icon
|
|
15
|
+
<StatusIndicator.Icon icon={cloudArrowUpIcon} />
|
|
16
16
|
<StatusIndicator.Label>Unpublished</StatusIndicator.Label>
|
|
17
17
|
</StatusIndicator>
|
|
18
18
|
<StatusIndicator variant="positive">
|
|
19
19
|
<StatusIndicator.Label>published</StatusIndicator.Label>
|
|
20
|
-
<StatusIndicator.Icon
|
|
20
|
+
<StatusIndicator.Icon icon={cloudArrowUpIcon} />
|
|
21
21
|
</StatusIndicator>
|
|
22
22
|
</Flex>
|
|
23
23
|
);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {ExampleCodeBlock, SymbolDoc} from '@workday/canvas-kit-docs';
|
|
2
|
+
import Alt from './examples/Alt';
|
|
2
3
|
import Basic from './examples/Basic';
|
|
3
4
|
import Focus from './examples/Focus';
|
|
4
|
-
|
|
5
|
+
|
|
5
6
|
|
|
6
7
|
# Canvas Kit Dialog
|
|
7
8
|
|
|
@@ -18,16 +19,17 @@ yarn add @workday/canvas-kit-react
|
|
|
18
19
|
|
|
19
20
|
### Basic Example
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
should be used in situations where the task does not require immediate attention.
|
|
22
|
+
The following example shows a typical Dialog with heading, close control, and form content.
|
|
23
23
|
|
|
24
24
|
<ExampleCodeBlock code={Basic} />
|
|
25
25
|
|
|
26
26
|
### Focus Redirect
|
|
27
27
|
|
|
28
|
-
Dialog **does not** trap keyboard focus like the Modal component does.
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
Dialog **does not** trap keyboard focus like the Modal component does. The default `useDialogModel`
|
|
29
|
+
composes `useFocusRedirect`: <kbd>Tab</kbd> / <kbd>Shift</kbd>+<kbd>Tab</kbd> at the last or first
|
|
30
|
+
focusable element inside the dialog closes it and moves focus to the next or previous focusable
|
|
31
|
+
element on the page. Dialog is non-modal and is **not** a focus trap; it does **not** change screen
|
|
32
|
+
reader reading order. The following example shows how Dialog manages focus at those edges.
|
|
31
33
|
|
|
32
34
|
<ExampleCodeBlock code={Focus} />
|
|
33
35
|
|
|
@@ -36,53 +38,238 @@ shows how Dialog manages focus in and out of the component.
|
|
|
36
38
|
|
|
37
39
|
### Alt Example
|
|
38
40
|
|
|
39
|
-
The `alt` variant is designed for use on alternative page backgrounds
|
|
41
|
+
The `alt` variant is designed for use on alternative page backgrounds
|
|
42
|
+
(`system.color.bg.alt.default`). Use this variant to maintain proper visual hierarchy when placing
|
|
43
|
+
components on colored backgrounds. While the default variant should be used on
|
|
44
|
+
`system.color.bg.default` backgrounds, the `alt` variant ensures the component remains visually
|
|
45
|
+
elevated on `system.color.bg.alt.default` backgrounds.
|
|
40
46
|
|
|
41
47
|
<ExampleCodeBlock code={Alt} />
|
|
42
48
|
|
|
43
49
|
## Accessibility
|
|
44
50
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
[Dialog Pattern
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
51
|
+
Ensure users of assistive technology can discover, name, and operate a **non-modal** dialog: the
|
|
52
|
+
rest of the page stays available (no inert background), the dialog has an accessible name that
|
|
53
|
+
matches its visible heading, keyboard users can open and dismiss it predictably, and screen reader
|
|
54
|
+
reading order is improved where `aria-owns` is supported (see
|
|
55
|
+
[Guides > Accessibility > Inline Popups](https://workday.github.io/canvas-kit/?path=/docs/guides-accessibility-inline-popups--docs)).
|
|
56
|
+
For blocking tasks, use
|
|
57
|
+
[**Modal**](https://workday.github.io/canvas-kit/?path=/docs/components-popups-modal--docs) instead.
|
|
58
|
+
Prefer **Dialog** for the standard non-modal dialog; use
|
|
59
|
+
[**Popup**](https://workday.github.io/canvas-kit/?path=/docs/components-popups-popup--docs) with
|
|
60
|
+
composed hooks when you need a custom popup stack or behavior (for example omitting
|
|
61
|
+
**`useInitialFocus`**). The W3C
|
|
62
|
+
[Dialog (Modal) Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/) applies to
|
|
63
|
+
[**Modal**](https://workday.github.io/canvas-kit/?path=/docs/components-popups-modal--docs); Dialog
|
|
64
|
+
is intentionally non-modal.
|
|
65
|
+
|
|
66
|
+
### Minimum Accessible Structure
|
|
67
|
+
|
|
68
|
+
The following matches the [Basic Example](#basic-example) layout: **`Dialog.CloseIcon`** before
|
|
69
|
+
**`Dialog.Heading`** so open focus lands on the dismiss control first; primary actions use
|
|
70
|
+
**`Dialog.CloseButton`** (which closes the dialog on activate).
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import {PrimaryButton} from '@workday/canvas-kit-react/button';
|
|
74
|
+
import {Dialog} from '@workday/canvas-kit-react/dialog';
|
|
75
|
+
import {FormField} from '@workday/canvas-kit-react/form-field';
|
|
76
|
+
import {TextInput} from '@workday/canvas-kit-react/text-input';
|
|
77
|
+
|
|
78
|
+
<Dialog>
|
|
79
|
+
<Dialog.Target as={PrimaryButton}>Open</Dialog.Target>
|
|
80
|
+
<Dialog.Popper>
|
|
81
|
+
<Dialog.Card>
|
|
82
|
+
<Dialog.CloseIcon aria-label="Close" />
|
|
83
|
+
<Dialog.Heading>Title</Dialog.Heading>
|
|
84
|
+
<Dialog.Body>
|
|
85
|
+
<FormField>
|
|
86
|
+
<FormField.Label>Email</FormField.Label>
|
|
87
|
+
<FormField.Input as={TextInput} />
|
|
88
|
+
</FormField>
|
|
89
|
+
</Dialog.Body>
|
|
90
|
+
<Dialog.ButtonGroup>
|
|
91
|
+
<Dialog.CloseButton>Cancel</Dialog.CloseButton>
|
|
92
|
+
<Dialog.CloseButton as={PrimaryButton}>Submit</Dialog.CloseButton>
|
|
93
|
+
</Dialog.ButtonGroup>
|
|
94
|
+
</Dialog.Card>
|
|
95
|
+
</Dialog.Popper>
|
|
96
|
+
</Dialog>;
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Include a dismiss control: **`Dialog.CloseButton`** with visible text (for example "Cancel" or
|
|
100
|
+
"Close"), and/or **`Dialog.CloseIcon`** when the design uses an icon-only dismiss (requires
|
|
101
|
+
**`aria-label`** or **`Tooltip`**). Use **`Dialog.CloseButton`** for actions that should also close
|
|
102
|
+
the dialog (for example "Submit").
|
|
103
|
+
|
|
104
|
+
### Built-in Behaviors
|
|
105
|
+
|
|
106
|
+
Canvas Kit applies these automatically via `useDialogModel` and Dialog subcomponents. **Do not
|
|
107
|
+
duplicate them** in consuming code.
|
|
108
|
+
|
|
109
|
+
**Popup behaviors** (_composed on the default model_):
|
|
110
|
+
|
|
111
|
+
- `useInitialFocus` — moves focus into the dialog when it opens (default: first focusable element in
|
|
112
|
+
DOM order; optional override via `initialFocusRef` on the model)
|
|
113
|
+
- `useReturnFocus` — returns focus to `Dialog.Target` (or configured return target) when it closes
|
|
114
|
+
- `useCloseOnEscape` — <kbd>Escape</kbd> closes the dialog
|
|
115
|
+
- `useCloseOnOutsideClick` — pointer interaction outside closes the dialog
|
|
116
|
+
- `useFocusRedirect` — <kbd>Tab</kbd> / <kbd>Shift</kbd>+<kbd>Tab</kbd> at the first or last
|
|
117
|
+
focusable element inside the dialog closes it and moves focus to the next or previous focusable
|
|
118
|
+
element on the page (non-modal; **not** a focus trap; does **not** change screen reader reading
|
|
119
|
+
order)
|
|
120
|
+
|
|
121
|
+
**ARIA and DOM** (_applied by hooks/subcomponents_):
|
|
122
|
+
|
|
123
|
+
- `Dialog.Card`: `role="dialog"`, `aria-labelledby` referencing the heading `id` (non-modal; page
|
|
124
|
+
content is not hidden with `aria-hidden`)
|
|
125
|
+
- `Dialog.Popper`: sibling wrapper rendered when open with `aria-owns` pointing at `Dialog.Card` to
|
|
126
|
+
remap the accessibility tree for sequential reading order in supported browsers
|
|
127
|
+
- `Dialog.Heading`: `id` wired to `Dialog.Card`'s `aria-labelledby`
|
|
128
|
+
- `Dialog.CloseIcon` / `Dialog.CloseButton`: `onClick` that calls `model.events.hide()`
|
|
129
|
+
- `Dialog.Target`: `ref` and `onClick` to open and to receive return focus
|
|
130
|
+
|
|
131
|
+
**Keyboard** (_trigger is `Dialog.Target`, default `SecondaryButton`_):
|
|
132
|
+
|
|
133
|
+
- <kbd>Enter</kbd> / <kbd>Space</kbd> on the trigger opens the dialog (standard button behavior)
|
|
134
|
+
- On open and close, focus is managed by **`useInitialFocus`** and **`useReturnFocus`** (application
|
|
135
|
+
overrides: see **Focus management** in Accessibility Requirements)
|
|
136
|
+
- <kbd>Tab</kbd> / <kbd>Shift</kbd>+<kbd>Tab</kbd> move focus forward and backward through
|
|
137
|
+
interactive elements inside the dialog (standard sequential focus behavior)
|
|
138
|
+
- <kbd>Escape</kbd> closes the dialog and returns focus per `useReturnFocus`
|
|
139
|
+
|
|
140
|
+
**Screen reader expectations** (_when built-in behaviors are used as intended_):
|
|
141
|
+
|
|
142
|
+
- On open, assistive technology should announce the first focused control (often a dismiss control),
|
|
143
|
+
the dialog name (`Dialog.Heading`), and `dialog` role
|
|
144
|
+
- Background page content remains available to assistive technology—Dialog does **not** apply
|
|
145
|
+
**`aria-hidden`** to siblings or render the rest of the page inert (unlike
|
|
146
|
+
[**Modal**](https://workday.github.io/canvas-kit/?path=/docs/components-popups-modal--docs))
|
|
147
|
+
- Reading order may follow on-screen order where `aria-owns` is honored; support varies by browser
|
|
148
|
+
and screen reader
|
|
149
|
+
|
|
150
|
+
### Accessibility Requirements
|
|
151
|
+
|
|
152
|
+
Required in application code for an accessible Dialog. Hoist **`useDialogModel`** when you need to
|
|
153
|
+
configure focus targets. Rows marked _(conditional)_ apply only when the situation matches—otherwise
|
|
154
|
+
omit.
|
|
155
|
+
|
|
156
|
+
**If no design spec is provided:** use default focus behavior; omit **`initialFocusRef`**,
|
|
157
|
+
**`returnFocusRef`**, **`aria-describedby`**, **`aria-expanded`**, and **`aria-haspopup`**.
|
|
158
|
+
|
|
159
|
+
**Focus management — defaults and developer prompts:** Canvas Kit handles open and close focus
|
|
160
|
+
automatically. **State the default to the developer first.** Only set **`initialFocusRef`** or
|
|
161
|
+
**`returnFocusRef`** after the developer (or an explicit design spec) chooses a non-default target.
|
|
162
|
+
**Do not generate focus refs by default.**
|
|
163
|
+
|
|
164
|
+
| When | Default behavior | Ask the developer before overriding |
|
|
165
|
+
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
166
|
+
| Dialog **opens** | **`useInitialFocus`** moves focus to the **first focusable element** in DOM order inside the dialog (often **`Dialog.CloseIcon`** or **`Dialog.CloseButton`**). Omit **`initialFocusRef`**. | _Which element should receive focus when the dialog opens?_ (Only when the default first focusable element is wrong for the design.) Attach **`initialFocusRef`** to that element on **`useDialogModel`**. |
|
|
167
|
+
| Dialog **closes** | **`useReturnFocus`** moves focus to **`Dialog.Target`**. Omit **`returnFocusRef`**. | _Which element should receive focus when the dialog closes?_ (Only when return focus should land somewhere other than **`Dialog.Target`**.) |
|
|
168
|
+
|
|
169
|
+
If close **removes the trigger from the DOM**, **`returnFocusRef`** alone is not enough—move focus
|
|
170
|
+
after the UI updates (for example with **`useLayoutEffect`**). See
|
|
171
|
+
[Modal > Return Focus](https://workday.github.io/canvas-kit/?path=/docs/components-popups-modal--docs#return-focus).
|
|
172
|
+
|
|
173
|
+
**Custom targets** _(conditional)_: Apply when using a custom **`as`** component on
|
|
174
|
+
**`Dialog.Target`**. **`Dialog.Target`** adds **`onClick`** and **`ref`**. Custom targets must
|
|
175
|
+
forward both to a **keyboard-focusable** element (prefer a native **`<button>`** or
|
|
176
|
+
**`as={SecondaryButton}`** / another Canvas Kit button). Wrap the component in
|
|
177
|
+
**`React.forwardRef`** when it does not forward refs by default (required if the dialog can open
|
|
178
|
+
programmatically before the user clicks the target).
|
|
179
|
+
|
|
180
|
+
| Requirement | How to satisfy |
|
|
181
|
+
| ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
182
|
+
| Accessible dialog name | Use **`Dialog.Heading`** so `aria-labelledby` on `Dialog.Card` references a visible title. Do not omit the heading: **`Dialog.Card` always sets `aria-labelledby`**, and an `aria-label` fallback is unreliable when that ID does not exist. |
|
|
183
|
+
| Dismiss control | Provide a way to close the dialog: **`Dialog.CloseButton`** with visible text (no extra **`aria-label`** needed), and/or **`Dialog.CloseIcon`** for icon-only dismiss (requires **`Tooltip`** or translated **`aria-label`**). |
|
|
184
|
+
| Keyboard-operable trigger | See **Custom targets** above. |
|
|
185
|
+
| Supplementary copy when overriding open focus _(conditional)_ | When **`initialFocusRef`** places open focus **below** **`Dialog.Heading`**, assign a unique `id` to supplementary text and pass **`aria-describedby`** on **`Dialog.Card`**. See **Open focus below the heading** below and [Popup > Initial Focus](https://workday.github.io/canvas-kit/?path=/docs/components-popups-popup--docs#initial-focus) (button-focus variant). |
|
|
186
|
+
| Open/closed state on the trigger _(conditional)_ | See **Wiring aria-expanded** below. **Default:** omit **`aria-expanded`** and **`aria-haspopup`**. |
|
|
187
|
+
|
|
188
|
+
**Open focus below the heading** _(conditional; see supplementary copy row above)_:
|
|
189
|
+
|
|
190
|
+
When open focus moves past the heading (for example into a form field), wire **`aria-describedby`**
|
|
191
|
+
so assistive technology still announces the supplementary copy. For focusing a primary action
|
|
192
|
+
instead of an input, see
|
|
193
|
+
[Popup > Initial Focus](https://workday.github.io/canvas-kit/?path=/docs/components-popups-popup--docs#initial-focus).
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
import React from 'react';
|
|
197
|
+
|
|
198
|
+
import {useUniqueId} from '@workday/canvas-kit-react/common';
|
|
199
|
+
import {Dialog, useDialogModel} from '@workday/canvas-kit-react/dialog';
|
|
200
|
+
import {FormField} from '@workday/canvas-kit-react/form-field';
|
|
201
|
+
import {TextInput} from '@workday/canvas-kit-react/text-input';
|
|
202
|
+
|
|
203
|
+
const Example = () => {
|
|
204
|
+
const descriptionId = useUniqueId();
|
|
205
|
+
const inputRef = React.useRef<HTMLInputElement>(null);
|
|
206
|
+
const model = useDialogModel({initialFocusRef: inputRef});
|
|
207
|
+
|
|
208
|
+
return (
|
|
209
|
+
<Dialog model={model}>
|
|
210
|
+
<Dialog.Target>Open</Dialog.Target>
|
|
211
|
+
<Dialog.Popper>
|
|
212
|
+
<Dialog.Card aria-describedby={descriptionId}>
|
|
213
|
+
<Dialog.CloseIcon aria-label="Close" />
|
|
214
|
+
<Dialog.Heading>Title</Dialog.Heading>
|
|
215
|
+
<Dialog.Body>
|
|
216
|
+
<p id={descriptionId}>Enter your email to continue.</p>
|
|
217
|
+
<FormField>
|
|
218
|
+
<FormField.Label>Email</FormField.Label>
|
|
219
|
+
<FormField.Input as={TextInput} ref={inputRef} />
|
|
220
|
+
</FormField>
|
|
221
|
+
</Dialog.Body>
|
|
222
|
+
<Dialog.CloseButton>Cancel</Dialog.CloseButton>
|
|
223
|
+
</Dialog.Card>
|
|
224
|
+
</Dialog.Popper>
|
|
225
|
+
</Dialog>
|
|
226
|
+
);
|
|
227
|
+
};
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**Summary for code generation:**
|
|
231
|
+
|
|
232
|
+
- **REQUIRED:** accessible name, dismiss control, keyboard-operable trigger
|
|
233
|
+
- **CONDITIONAL:** **`initialFocusRef`**, **`returnFocusRef`**, **`aria-describedby`**,
|
|
234
|
+
**`aria-expanded`** / **`aria-haspopup`**, **`forwardRef`** on custom **`Dialog.Target`**
|
|
235
|
+
|
|
236
|
+
**Wiring aria-expanded** _(conditional)_:
|
|
237
|
+
|
|
238
|
+
The **`aria-expanded`** pattern is **uncommon** for Dialog—omit **`aria-expanded`** and
|
|
239
|
+
**`aria-haspopup`** unless a review deliberately keeps open focus on the trigger (for example
|
|
240
|
+
**`initialFocusRef`** on the trigger per design spec). When required, on **`Dialog.Target`** set
|
|
241
|
+
**`aria-expanded={model.state.visibility !== 'hidden'}`** and **`aria-haspopup="dialog"`**. See
|
|
242
|
+
**Focus management** and the open/closed-state row above. If the design should not move focus into
|
|
243
|
+
the dialog on open, use
|
|
244
|
+
[**Popup**](https://workday.github.io/canvas-kit/?path=/docs/components-popups-popup--docs) with
|
|
245
|
+
composed hooks instead of overriding Dialog defaults.
|
|
246
|
+
|
|
247
|
+
### Anti-Patterns
|
|
248
|
+
|
|
249
|
+
Do **not** generate code that does the following (see **Accessibility Requirements** above for what
|
|
250
|
+
to supply instead):
|
|
251
|
+
|
|
252
|
+
- Manually set `role="dialog"`, `aria-labelledby`, `aria-owns`, or dialog `id` on **`Dialog.Card`**,
|
|
253
|
+
**`Dialog.Popper`**, or **`Dialog.Heading`** — Canvas Kit hooks wire these
|
|
254
|
+
- Omit **`Dialog.Popper`**, render **`Dialog.Card`** outside it, or add a custom portal/restructure
|
|
255
|
+
instead of **`Dialog` → `Dialog.Popper` → `Dialog.Card`**
|
|
256
|
+
- Use **`open`** / **`onClose`** props on **`Dialog`** — Dialog has no controlled visibility props;
|
|
257
|
+
use **`useDialogModel`** and **`model.events.show()`** / **`model.events.hide()`**
|
|
258
|
+
- Add **`useFocusTrap`**, **`aria-modal="true"`**, or **`aria-hidden`** on page siblings expecting
|
|
259
|
+
modal behavior — Dialog is intentionally non-modal
|
|
260
|
+
- Use **Modal** when the task is non-critical or the rest of the page must stay operable
|
|
261
|
+
- Set **`initialFocusRef`** or **`returnFocusRef`** by default — state the default focus behavior
|
|
262
|
+
first and ask the developer before overriding (see **Focus management** in Accessibility
|
|
263
|
+
Requirements)
|
|
264
|
+
- Add **`aria-expanded`** / **`aria-haspopup`** on the default Dialog path, or bind
|
|
265
|
+
**`aria-expanded`** to a static value (see **Wiring aria-expanded** in Accessibility Requirements)
|
|
266
|
+
- Use a custom **`Dialog.Target`** **`as`** component that does not forward **`ref`** to a focusable
|
|
267
|
+
element — use **`React.forwardRef`** or a Canvas Kit button component instead
|
|
268
|
+
- Rely on **`returnFocusRef`** alone when close **removes the trigger from the DOM** (see
|
|
269
|
+
[Modal > Return Focus](https://workday.github.io/canvas-kit/?path=/docs/components-popups-modal--docs#return-focus))
|
|
270
|
+
- Nest multiple **`Dialog`** instances without deliberate initial focus and return-focus planning
|
|
271
|
+
- Assume **`useFocusRedirect`** fixes screen reader reading order, or that **`aria-owns`** remapping
|
|
272
|
+
works in all browser and screen reader combinations — test your supported combinations
|
|
86
273
|
|
|
87
274
|
## Component API
|
|
88
275
|
|