Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(AriaLive): add new component #3217

Merged
merged 8 commits into from
Jan 17, 2024
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
## January, 18. 2024

- New component: [AriaLive](/uilib/components/aria-live)

## May, 31. 2023

- [New major version 10](/uilib/about-the-lib/releases/eufemia/v10-info/)
- New components released:
- [SkipContent](/uilib/components/skip-content)
- New component: [SkipContent](/uilib/components/skip-content)
- [GlobalError](/uilib/components/global-error) got new styles (without illustrations).
- New [Icons](/icons/secondary):
- `handshake`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title: 'AriaLive'
description: 'AriaLive is a React component and hook that helps make your web app more accessible by announcing dynamic changes to screen readers.'
showTabs: true
hideTabs:
- title: Events
theme: 'sbanken'
status: 'new'
---

import AriaLiveInfo from 'Docs/uilib/components/aria-live/info'
import AriaLiveDemos from 'Docs/uilib/components/aria-live/demos'

<AriaLiveInfo />
<AriaLiveDemos />
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/**
* UI lib Component Example
*
*/

import React from 'react'
import { Field, FieldBlock, Form } from '@dnb/eufemia/src/extensions/forms'
import ComponentBox from '../../../../shared/tags/ComponentBox'
import { AriaLive, Button, Flex, P } from '@dnb/eufemia/src'

export const AriaLivePlayground = () => (
<ComponentBox hideCode>
{() => {
const priorities = ['low', 'high']
const contents = {
default: 'This is a default announcement',
second: 'And a second one',
third: 'A third one',
fourth: 'And a fourth one',
}
const priority: 'low' | 'high' = 'low'
const defaultData = {
enabled: false,
content: contents.default,
priority,
}

function AriaLiveExample() {
const { data } = Form.useData('aria-live-playground', defaultData)

return (
<Form.Handler id="aria-live-playground">
<Flex.Stack>
<Field.Boolean label="Enabled" path="/enabled" />
<Field.Selection
variant="button"
optionsLayout="horizontal"
label="Priority"
path="/priority"
>
{priorities.map((content) => {
return (
<Field.Option
key={content}
title={content}
value={content}
/>
)
})}
</Field.Selection>

<Field.Selection
optionsLayout="horizontal"
label="Content"
path="/content"
>
{Object.entries(contents).map(([key, value]) => {
return (
<Field.Option key={key} title={key} value={value} />
)
})}
</Field.Selection>

<Field.String
label="Content as freetext"
path="/content"
multiline
/>

<Flex.Item>
Output:{' '}
<AriaLive
delay={1000}
disabled={!data.enabled}
priority={data.priority}
showAnnouncement
>
Message: {data.content}
</AriaLive>
</Flex.Item>
</Flex.Stack>
</Form.Handler>
)
}

return <AriaLiveExample />
}}
</ComponentBox>
)

export const AriaLiveAdditions = () => (
<ComponentBox hideCode scope={{ FieldBlock }}>
{() => {
const defaultData = {
enabled: false,
content: [<P key="one">Line 1</P>],
}

function AriaLiveExample() {
const { data, update } = Form.useData(
'aria-live-additions',
defaultData,
)

return (
<Form.Handler id="aria-live-additions">
<Flex.Stack>
<Field.Boolean label="Enabled" path="/enabled" />

<FieldBlock label="Content">
<Form.ButtonRow>
<Button
text="Add more content"
variant="secondary"
icon="add"
icon_position="left"
on_click={() => {
update('/content', (content) => {
const c = content.length + 1
content.push(<P key={c}>Line {c}</P>)
return content
})
}}
/>
<Button
text="Remove content"
variant="tertiary"
icon="subtract"
icon_position="left"
on_click={() => {
update('/content', (content) => {
content.pop()
return content
})
}}
/>
</Form.ButtonRow>
</FieldBlock>

<Flex.Item>
Output:{' '}
<AriaLive variant="content" disabled={!data.enabled}>
Message: {data.content}
</AriaLive>
</Flex.Item>
</Flex.Stack>
</Form.Handler>
)
}

return <AriaLiveExample />
}}
</ComponentBox>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
showTabs: true
---

import * as Examples from './Examples'

## Demos

### Playground

<Examples.AriaLivePlayground />

### Additions

<Examples.AriaLiveAdditions />
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
showTabs: true
---

## Description

AriaLive is a React component and hook that helps make your web app more accessible by adding or defining an ARIA live region that announces dynamic changes to screen readers.

Use it to manually inform users using a screen reader, about changes on the screen that isn't normally covered by screen readers.

By default, the `AriaLive` component will announce changes to the screen reader in a polite manner. This means that the announcement will wait until the screen reader is idle. This is the recommended way to use the component.

## Usage

For invisible text content:

```tsx
import { AriaLive } from '@dnb/eufemia'
render(<AriaLive>invisible message to announce</AriaLive>)
```

For content that is visible, but where changes need to be announced:

```tsx
import { AriaLive } from '@dnb/eufemia'
render(
<AriaLive variant="content">
<ul>
<li>item one</li>
<li>item two</li>
{/* When item three appears, it will be announced */}
</ul>
</AriaLive>,
)
```

## Priority

The `priority` prop in the `AriaLive` component is used to control the urgency of the announcement. It can be set to `high` (defaults to `low`). This allows you to control how assertive the announcement should be, helping to create a better user experience for users who rely on screen readers.

## AriaLive Hook

The `useAriaLive` hook is a part of the `AriaLive` component. It can be used to make announcements in functional components. In this example `<section>` is turned into an ARIA live region with all the functionality of the `<AriaLive>` component:

```tsx
import useAriaLive from '@dnb/eufemia/components/aria-live/useAriaLive'

function MyCustomAriaLive(props) {
const ariaAttributes = useAriaLive(props)
return <section {...ariaAttributes} />
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
showTabs: true
---

## Properties

| Properties | Types | Description |
| ------------------ | ----------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `variant` | `string` | _(optional)_ Can be `text` for text messages or `content` for whole application content. Defaults to `text`. |
| `priority` | `string` | _(optional)_ Priority of the announcement. Can be `low` or `high`. Defaults to `low`. |
| `delay` | `number` | _(optional)_ Delay in milliseconds before the announcement is made. Defaults to `1000`. |
| `disabled` | `boolean` | _(optional)_ If `true`, the announcement will not be made. Defaults to `false`. |
| `atomic` | `boolean` | _(optional)_ If `true`, assistive technologies will present the entire region as a whole. If `false`, only additions will be announced. |
| `politeness` | `string` | _(optional)_ The politeness setting for the announcement. Can be `polite` or `assertive`. |
| `relevant` | `string` | _(optional)_ A space-separated list of the types of changes that should be announced. Can be `additions`, `removals`, `text`, or `all`. |
| `showAnnouncement` | `boolean` | _(optional)_ Whether to show the children or not. |
| `children` | `ReactNode` | The content that will be announced to the user. |
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Eufemia includes a range of tools to help you make better accessible application
- [FieldBlock](!/uilib/extensions/forms/create-component/FieldBlock) handles `<fieldset>` and `<legend>`.
- [VisuallyHidden](!/uilib/components/visually-hidden) hides text visually, while makes it available for screen readers. Its based on the helper HTML class `dnb-sr-only`.
- [SkipContent](!/uilib/components/skip-content) similar to a skip link. It allows a user, while tabbing, to skip large parts of content, to reach quickly a save button etc.
- [AriaLive](/uilib/components/aria-live) is a component that makes it easy to announce messages to screen readers.

All form components includes a `label` property to bind automatically the FormLabel to the components (HTML element).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ description: 'Accessibility checklist to help you remember the most important ta
- [ ] Do never expose a form element as `disabled` to the user. Use good UX instead.
- [ ] Have a [Skip Link](/uilib/usage/accessibility/focus#skip-link) in place if the user has to tab many times to reach the main content.
- [ ] Use the [SkipContent](/uilib/components/skip-content/) helper to let the user skip large parts of content, while using keyboard navigation.
- [ ] Use the [AriaLive](/uilib/components/aria-live) component to automatically inform users using a screen reader, about changes on the screen that they didn't initiate.
- [ ] Make good use of [`aria-label`](/uilib/usage/accessibility/screenreader#usage-of-aria-label-aria-labelledby-and-aria-describedby) and `aria-hidden`, e.g. of [decorative content](/uilib/usage/accessibility/icons#decorative-icons).
- [ ] Make [images and illustrations](/uilib/usage/accessibility/screenreader#images-and-illustrations) accessible.
- [ ] Have `aria-live` in place for dynamic content, like updates coming from the server.
Expand Down
14 changes: 14 additions & 0 deletions packages/dnb-eufemia/src/components/AriaLive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* ATTENTION: This file is auto generated by using "prepareTemplates".
* Do not change the content!
*
*/

/**
* Library Index aria-live to autogenerate all the components and extensions
* Used by "prepareAriaLives"
*/

import AriaLive from './aria-live/AriaLive'
export * from './aria-live/AriaLive'
export default AriaLive
11 changes: 11 additions & 0 deletions packages/dnb-eufemia/src/components/aria-live/AriaLive.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react'
import { AriaLiveAllProps } from './types'
import useAriaLive from './useAriaLive'

export default function AriaLive(props: AriaLiveAllProps) {
const ariaAttributes = useAriaLive(props)

return <section {...ariaAttributes} />
}

AriaLive._supportsSpacingProps = 'children'
Loading
Loading