@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.
@@ -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.10",
22
- "@workday/canvas-kit-preview-react": "16.0.10",
23
- "@workday/canvas-kit-react": "16.0.10",
24
- "@workday/canvas-kit-react-fonts": "^16.0.10",
25
- "@workday/canvas-kit-styling": "16.0.10",
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.10",
23
- "@workday/canvas-kit-preview-react": "16.0.10",
24
- "@workday/canvas-kit-react": "16.0.10",
25
- "@workday/canvas-kit-react-fonts": "^16.0.10",
26
- "@workday/canvas-kit-styling": "16.0.10",
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 { ExampleCodeBlock, SymbolDoc } from '@workday/canvas-kit-docs';
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 aria-label="unpublished" icon={cloudArrowUpIcon} />
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 aria-label="published" icon={cloudArrowUpIcon} />
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
- import Alt from './examples/Alt';
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
- Unlike Modal, Dialog **does not** render the rest of the page inert while it is active. Dialog
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. Instead, it allows focus to
29
- move freely in and out of the dialog, supporting more flexible navigation. The following example
30
- shows how Dialog manages focus in and out of the component.
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 (`system.color.bg.alt.default`). Use this variant to maintain proper visual hierarchy when placing components on colored backgrounds. While the default variant should be used on `system.color.bg.default` backgrounds, the `alt` variant ensures the component remains visually elevated on `system.color.bg.alt.default` 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
- `Dialog` composes the popup stack with `useInitialFocus`, `useReturnFocus`, `useCloseOnEscape`,
46
- `useCloseOnOutsideClick`, and `useFocusRedirect`. The card container includes an ARIA
47
- **`role="dialog"`** that is **non-modal**: the rest of the page stays available. The card also
48
- includes an **`aria-labelledby`** attribute referencing the `id` on `Dialog.Heading`, so the dialog
49
- has an accessible name that matches the visible heading.
50
-
51
- The Dialog component includes a `<div>` element (sibling to the `Dialog.Target`) with `aria-owns`
52
- pointing to the `Dialog.Card`. This remaps the hierarchy of the accessibility tree to improve
53
- sequential reading order in supported browsers. For more information, see
54
- [Guides > Accessibility > Inline Popups](https://workday.github.io/canvas-kit/?path=/docs/guides-accessibility-inline-popups--docs).
55
-
56
- [Dialog Pattern | APG | WAI | W3C](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/)
57
-
58
- - Prefer **`Dialog.Heading`** so the dialog is properly labelled; avoid leaving a dialog without an
59
- accessible name.
60
- - Ensure icon-only controls such as **`Dialog.CloseIcon`** include an accessible name. Prefer the
61
- `Tooltip` component to provide a visible label, or a translated `aria-label` string is acceptable.
62
-
63
- ### Navigation
64
-
65
- - **Enter** / **Space**: Open the dialog (standard button behavior on the trigger). When it opens,
66
- focus moves to the **first focusable element** inside the dialog in DOM order—often the close
67
- control—or to the element referenced by **`initialFocusRef`** on the dialog model when set.
68
- - **Tab** / **Shift + Tab**: Move through focusable elements inside the dialog; leaving the first or
69
- last focusable element **closes** the dialog and moves focus to the next or previous focusable
70
- element on the page (non-modal focus redirect behavior).
71
- - **Escape**: Closes the dialog and returns focus to the `Dialog.Target` (or configured return
72
- target).
73
-
74
- ### Screen Reader Experience
75
-
76
- - **When the dialog opens:** Screen readers should announce the name and role of the first focused
77
- control (often the close button), the dialog's name (`Dialog.Heading`) and role.
78
- - **Reading order:** The dialog contents should be read in the same order as it appears on screen
79
- for browsers and screen readers that support `aria-owns`. Results vary, so always test with your
80
- supported browsers and screen reader combinations.
81
- - **Expanded or collapsed state:** The `Dialog.Target` does not include an expanded or collapsed
82
- state by default, but it can be added if the interaction design isn't using an initial focus for
83
- the Dialog. See
84
- [Guides > Accessibility > Inline Popups](https://workday.github.io/canvas-kit/?path=/docs/guides-accessibility-inline-popups--docs)
85
- for more information.
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