Skip to content

Commit

Permalink
docs: Fixing NotificationBadge storybook example (#2903)
Browse files Browse the repository at this point in the history
I had been researching how to use `AriaLiveRegion` with the notification badges in the `GlobalHeader` storybook example, and noticed the `aria-live` regions were being used incorrectly here in this example.

[category:Documentation, examples]

Co-authored-by: William Stanton <[email protected]>
  • Loading branch information
williamjstanton and William Stanton authored Sep 16, 2024
1 parent 6a3bca7 commit e5e4e8f
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 138 deletions.

This file was deleted.

29 changes: 14 additions & 15 deletions modules/react/badge/stories/CountBadge.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,20 @@ messages on their first day back.

### Notification Badge

Notifications are a major use case for `CountBadge`. Remember that any `CountBadge` with a
live-updating value should be announced to screen readers with an `aria-live` region and an
`aria-label` on the button to provide additional context, as in the example below. Please also read
the Accessibility guidance below this example for aditional information.
Notifications are a major use case for `CountBadge`. When the `CountBadge` value is updated in
real-time, screen readers must be supported with an `AriaLiveRegion` that will automatically
describe the change in the number of notifications. If the web app only updates `CountBadge` as part
of another screen update, then this use of `AriaLiveRegion` is unnecessary and not recommended.

#### Notes on accessibility for the example below

- `Tooltip` is set on the `SecondaryButton` automatically applying the `aria-label` to the button.
- `aria-describedby` property is conditionally set on the `SecondaryButton` when greater than zero
referencing a unique `id` for the `CountBadge` value .
- `AriaLiveRegion` is used around the `CountBadge`, enabling screen readers to monitor changes in
value.
- `aria-label` string is conditionally set on `AriaLiveRegion` when greater than zero, describing
"New notification"

<ExampleCodeBlock code={NotificationBadge} />

Expand All @@ -55,17 +65,6 @@ the Accessibility guidance below this example for aditional information.
Count Badge supports custom styling via the `cs` prop. For more information, check our
["How To Customize Styles"](https://workday.github.io/canvas-kit/?path=/docs/styling-how-to-customize-styles--page).

## Accessibility

A common use case for `CountBadge` is displaying notifications, but there are other situations where
they will have live-updated values. There are several accessibility concerns you'll want to keep in
mind:

- The button should have an aria-label that updates with the count
- The elements inside the button should have `aria-hidden`
- The live region should be outside the button
- The live region should be visually hidden and only contain text

## Component API

<SymbolDoc name="CountBadge" fileName="/react/" />
55 changes: 30 additions & 25 deletions modules/react/badge/stories/examples/NotificationBadge.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
import * as React from 'react';
import {CountBadge} from '@workday/canvas-kit-react/badge';
import {SecondaryButton, TertiaryButton} from '@workday/canvas-kit-react/button';
import {accessibleHide} from '@workday/canvas-kit-react/common';
import {AriaLiveRegion, useUniqueId} from '@workday/canvas-kit-react/common';
import {createStyles, cssVar} from '@workday/canvas-kit-styling';
import {notificationsIcon} from '@workday/canvas-system-icons-web';
import {base, system} from '@workday/canvas-tokens-web';
import {Tooltip} from '@workday/canvas-kit-react/tooltip';
import {Flex} from '@workday/canvas-kit-react/layout';

function negate(value: string, fallback?: string) {
return `calc(${cssVar(value, fallback)} * -1)`;
}

const container = createStyles({
boxSizing: 'border-box',
display: 'flex',
flexDirection: 'column',
gap: system.space.x4,
});

const controls = createStyles({
boxSizing: 'border-box',
borderBottom: `solid 1px ${cssVar(base.soap400)}`,
display: 'flex',
gap: system.space.x1,
gap: system.space.x2,
padding: system.space.x1,
});

Expand All @@ -33,40 +32,46 @@ const notificationContainerStyles = createStyles({
const countBadgeStyles = createStyles({
boxSizing: 'border-box',
position: 'absolute',
top: negate(system.space.x4),
top: negate(system.space.x1),
insetInlineEnd: negate(system.space.x1),
});

const accessibleHideStyles = createStyles(accessibleHide);

// Testing notes (Aug. 30, 2024):
// Windows 11
// JAWS 2024 + Chrome / Edge: "New notifications" once, then only the count change "2"
// JAWS 2024 + FF: "New notifications" once, then describes nothing
// NVDA + Chrome / Edge: Consistently describes "{X} New notifications"
// NVDA + FF: Consistently describes count value only "{X}"
// macOS v14.6.1
// VoiceOver + Chrome / Safari: Consistently describes "New notifications {X}"
export function NotificationBadge() {
const [count, setCount] = React.useState(4);
const badgeID = useUniqueId();

return (
<div className={container}>
<div className={controls}>
<Flex cs={container}>
<Flex cs={controls}>
<TertiaryButton size="small" onClick={() => setCount(count + 1)}>
Add Notification
</TertiaryButton>
<TertiaryButton size="small" onClick={() => setCount(0)}>
Clear
</TertiaryButton>
</div>
<div>
</Flex>
<Flex>
<span className={notificationContainerStyles}>
<SecondaryButton
aria-label={`Alerts ${count} new notifications`}
size="medium"
icon={notificationsIcon}
/>
{!!count && (
<CountBadge count={count} limit={100} aria-hidden="true" cs={countBadgeStyles} />
)}
<div className={accessibleHideStyles} role="status" aria-live="polite" aria-atomic="true">
New notifications
</div>
<Tooltip title="Notifications">
<SecondaryButton
size="medium"
icon={notificationsIcon}
aria-describedby={!!count ? badgeID : undefined}
/>
</Tooltip>
<AriaLiveRegion aria-label={!!count ? 'New notifications' : undefined}>
{!!count && <CountBadge id={badgeID} count={count} limit={100} cs={countBadgeStyles} />}
</AriaLiveRegion>
</span>
</div>
</div>
</Flex>
</Flex>
);
}

0 comments on commit e5e4e8f

Please sign in to comment.