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(documentation): Reorganized Accessibility folder and added Form Grouping Controls Section #3638

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fast-fans-wash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@swisspost/design-system-documentation': minor
---

Updated the Accessibility documentation, reorganized in mutliple folders and added Grouping Controls section
5 changes: 5 additions & 0 deletions .changeset/proud-moons-impress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@swisspost/design-system-documentation': patch
---

Updated the text of the Accessibility Forms Control Grouping section and corrected the last example
Original file line number Diff line number Diff line change
@@ -1,27 +1,13 @@
import { Meta, Source, Canvas } from '@storybook/blocks';
import * as AccessibilityStories from './accessibility.stories';
import liveRegionAtomicSample from './liveregion-atomic.sample.html?raw';
import liveRegionGoodAngularSample from './liveregion-good-angular.sample.html?raw';
import liveRegionBadAngularSample from './liveregion-bad-angular.sample.html?raw';
import * as FormsStories from './forms.stories';

<Meta of={AccessibilityStories} />

# Accessibility
<Meta of={FormsStories} />

<figure>
<blockquote class="blockquote" lang="de">
<p>Die Postdienste müssen so angeboten werden, dass Menschen mit Behinderungen
sie in qualitativer, quantitativer und wirtschaftlicher Hinsicht unter vergleichbaren
Bedingungen wie Menschen ohne Behinderungen beanspruchen können.</p>
</blockquote>
<figcaption class="blockquote-footer">
<cite>§14.7 <a href="https://www.fedlex.admin.ch/eli/cc/2012/585/de#art_14">Swiss postal law</a></cite>
</figcaption>
</figure>

## Forms
# Forms

### Disabled state
## Disabled state

Disabled states of input fields or buttons pose many accessibility issues.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also fix the wrong implementation of ul / li elements?
A div is semantically wrong here and not allowed as a child in an ul element.

Should be implemented somehow like this:

<ul class="list-unstyled">
  <li class="d-flex gap-mini">
    <div></div><div>List Item text</div>
  </li>
</ul>

Do this for all ul / li constructs on the page, which are using ❌ or ✔️ as marker/icon.

Expand Down Expand Up @@ -102,51 +88,74 @@ Disabled states of input fields or buttons pose many accessibility issues.

### Form bad example

<Canvas of={AccessibilityStories.FormBadExample}/>
<Canvas of={FormsStories.FormBadExample}/>

### Form good example

<Canvas of={AccessibilityStories.FormGoodExample}/>
<Canvas of={FormsStories.FormGoodExample}/>

## Live region

A live region allows you to notify the user about a dynamic change without requiring the page to reload e.g. alert, loading status, chat logs, update of a product cart, feeds, etc.

They are defined either by using the `aria-live` attribute or some specific `role` attributes such as `role=status`, `role=alert`, `role=log`, etc.
## Controls Grouping

### Implicit aria-live attribute with role attribute
When grouping `<form controls>`, the `<fieldset>`and `<legend>` elements play a critical role in providing context to screen readers. However, improper usage of these elements can lead to confusion for users with disabilities.

`role=status`, `role=log` and `role=alert` have an implicit default `aria-live` attribute, however for a maximum compatibility, it is recommended to add it as well (except for `role=alert`). Source: [Roles with implicit live region attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions#roles_with_implicit_live_region_attributes)

### Choose the appropriate value for the aria-live attribute

`aria-live` attribute can be either:
* `polite`: message will be announced after the screen reader is idle.
* `assertive`: message will interrupt any announcement immediately. It should be used sparingly.

### Announce the whole Live region on change

By default, screen readers will only announce the part that changed. However, it's often better to repeat the context of the change.
To do so, we can add `aria-atomic=true` attribute on the live region. This attribute force screen readers to read the whole text.

For example on a shopping website, you want to announce to the user that a product was added to the shopping basket. If you announce only the product name, it's not enough to be comprehensive.

<Source code={liveRegionAtomicSample} language="html" />

### Add or remove dynamically a live region
<div class="table-responsive">
<table className="table caption-top">
<caption>Common mistakes and how to avoid them.</caption>
<colgroup>
<col style={{width: '50%'}} />
<col style={{width: '50%'}} />
</colgroup>
<tbody>
<tr>
<td colSpan="2" class="fw-bold">The `<legend>` element is not a direct child of the `<fieldset>`</td>
</tr>
<tr>
<td>
<ul class="list-unstyled d-flex gap-mini">
<div>❌</div><li>A `<div>` or other element is incorrectly used as the first child of a `<fieldset>` with the `<legend>` nested inside this element.</li>
</ul>

</td>
<td>
<ul class="list-unstyled d-flex gap-mini">
<div>✔️</div><li>Always place the `<legend>` right after the `<fieldset>` to preserve the association.</li>
</ul>
</td>
</tr>
<tr>
<td colSpan="2" class="fw-bold">A `<div>` is used for grouping instead of `<fieldset>`</td>
</tr>
<tr>
<td>
<ul class="list-unstyled d-flex gap-mini">
<div>❌</div><li>For visual reasons, a `<div>` is used for grouping controls instead of `<fieldset>`. No ARIA roles or attributes are set, failing to provide the necessary semantic meaning on assistive technologies.</li>
</ul>

</td>
<td>
<ul class="list-unstyled d-flex gap-mini">
<div>✔️</div><li>Assign the `role="group"` to the `<div>` element to provide it with the semantic meaning of a `<fieldset>`. Use `aria-labelledby` or `aria-describedby` to associate any descriptive text with the grouping container to ensure that screen readers can provide context to users.</li>
</ul>
</td>
</tr>

</tbody>
</table>
</div>

As a best practice, live region should be present on the page load and only the content inside it should change.

#### Example with a spinner on Angular
### The wrong way

When adding, for example, a spinner above a section, the live region container should be rendered initially while you can use `ng-container` to show and hide the spinner when you need it.
<Canvas of={FormsStories.FieldsetDontExample}/>

##### Good example
### Recommended ways

<Source code={liveRegionGoodAngularSample} language="html" />
#### Standard

##### Bad example
<Canvas of={FormsStories.FieldsetDoExample}/>

You shouldn't add the whole region dynamically as the accessibility bindings might not be [updated with some screen readers](https://www.scottohara.me/blog/2022/02/05/are-we-live.html#non-normative-rule-for-common-live-region-use-case).
#### Alternative using div

<Source code={liveRegionBadAngularSample} language="html" />
<Canvas of={FormsStories.DivForGroupingExample}/>
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { MetaExtended } from '@root/types';
import { html } from 'lit';

const meta: MetaExtended = {
id: '46da78e8-e83b-4ca1-aaf6-bbc662efef14',
title: 'Foundations/Accessibility',
id: 'cb34361c-7d3f-4c21-bb9c-874c73e82578',
title: 'Foundations/Accessibility/Forms',
parameters: {
badges: [],
},
Expand Down Expand Up @@ -299,3 +299,37 @@ export const FormBadExample: Story = {
addInputChangeListener();
</script>`,
};


export const FieldsetDontExample: Story = {
render: () => html`<fieldset>
<div>
<legend>Gender</legend>
<input type="radio" name="gender" value="male"> Male
<input type="radio" name="gender" value="female"> Female
</div>
</fieldset>`,
};



export const FieldsetDoExample: Story = {
render: () => html`<span id="group-description">Please select your gender:</span>
<fieldset>
<legend>Gender</legend>
<input type="radio" name="gender" value="male"> Male
<input type="radio" name="gender" value="female"> Female
</fieldset>`,
};




export const DivForGroupingExample: Story = {
render: () => html`<span id="group-description">Please select your gender:</span>
<div role="group" aria-labelledby="group-label "aria-describedby="group-description">
<span id="group-label" style="margin-right:5px">Gender </span>
Comment on lines +330 to +331
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These elements are not rendered on the page under the preview URL. Not sure why, do you have any idea?

<input type="radio" name="gender" value="male"> Male
<input type="radio" name="gender" value="female"> Female
</div>`,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Meta, Source, Canvas } from '@storybook/blocks';
import * as LiveRegionStories from './liveregion.stories';
import liveRegionAtomicSample from './liveregion-atomic.sample.html?raw';
import liveRegionGoodAngularSample from './liveregion-good-angular.sample.html?raw';
import liveRegionBadAngularSample from './liveregion-bad-angular.sample.html?raw';

<Meta of={LiveRegionStories} />


# Live region

A live region allows you to notify the user about a dynamic change without requiring the page to reload e.g. alert, loading status, chat logs, update of a product cart, feeds, etc.

They are defined either by using the `aria-live` attribute or some specific `role` attributes such as `role=status`, `role=alert`, `role=log`, etc.

## Implicit aria-live attribute with role attribute

`role=status`, `role=log` and `role=alert` have an implicit default `aria-live` attribute, however for a maximum compatibility, it is recommended to add it as well (except for `role=alert`). Source: [Roles with implicit live region attribute](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions#roles_with_implicit_live_region_attributes)

## Choose the appropriate value for the aria-live attribute

`aria-live` attribute can be either:
* `polite`: message will be announced after the screen reader is idle.
* `assertive`: message will interrupt any announcement immediately. It should be used sparingly.

## Announce the whole Live region on change

By default, screen readers will only announce the part that changed. However, it's often better to repeat the context of the change.
To do so, we can add `aria-atomic=true` attribute on the live region. This attribute force screen readers to read the whole text.

For example on a shopping website, you want to announce to the user that a product was added to the shopping basket. If you announce only the product name, it's not enough to be comprehensive.

<Source code={liveRegionAtomicSample} language="html" />

### Add or remove dynamically a live region

As a best practice, live region should be present on the page load and only the content inside it should change.

### Example with a spinner on Angular

When adding, for example, a spinner above a section, the live region container should be rendered initially while you can use `ng-container` to show and hide the spinner when you need it.

#### Good example

<Source code={liveRegionGoodAngularSample} language="html" />

#### Bad example

You shouldn't add the whole region dynamically as the accessibility bindings might not be [updated with some screen readers](https://www.scottohara.me/blog/2022/02/05/are-we-live.html#non-normative-rule-for-common-live-region-use-case).

<Source code={liveRegionBadAngularSample} language="html" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { StoryObj } from '@storybook/web-components';
import { MetaExtended } from '@root/types';
import { html } from 'lit';

const meta: MetaExtended = {
id: '548d973c-679c-4a02-96cd-70f82aec5f65',
title: 'Foundations/Accessibility/LiveRegion',
parameters: {
badges: [],
},
};

export default meta;

type Story = StoryObj;

export const Default: Story = {};
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Meta, Source, Canvas } from '@storybook/blocks';
import * as RegulationStories from './regulation.stories';

<Meta of={RegulationStories} />

# Accessibility

<figure>
<blockquote class="blockquote" lang="de">
<p>Die Postdienste müssen so angeboten werden, dass Menschen mit Behinderungen
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we translate this to english? For example with the post translater or with deepl or some other online service.

sie in qualitativer, quantitativer und wirtschaftlicher Hinsicht unter vergleichbaren
Bedingungen wie Menschen ohne Behinderungen beanspruchen können.</p>
</blockquote>
<figcaption class="blockquote-footer">
<cite>§14.7 <a href="https://www.fedlex.admin.ch/eli/cc/2012/585/de#art_14">Swiss postal law</a></cite>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the language can be choosen by the page itself, depending on the browser language.

Suggested change
<cite>§14.7 <a href="https://www.fedlex.admin.ch/eli/cc/2012/585/de#art_14">Swiss postal law</a></cite>
<cite>§14.7 <a href="https://www.fedlex.admin.ch/eli/cc/2012/585">Swiss postal law</a></cite>

</figcaption>
</figure>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { StoryObj } from '@storybook/web-components';
import { MetaExtended } from '@root/types';

const meta: MetaExtended = {
id: '759a427c-7884-474e-b6b7-de32d3acf5df',
title: 'Foundations/Accessibility/Regulation',
parameters: {
badges: [],
},
};

export default meta;

type Story = StoryObj;

export const Default: Story = {};
Loading