Skip to content

Commit

Permalink
Split ama documentation (#178)
Browse files Browse the repository at this point in the history
* accessibility role

* more documentation

* chore: restore home screen
  • Loading branch information
ceceppa authored Sep 18, 2023
1 parent 12672a4 commit a41f9b1
Show file tree
Hide file tree
Showing 11 changed files with 338 additions and 72 deletions.
File renamed without changes.
42 changes: 27 additions & 15 deletions docs/guidelines/accessibility-label.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
ama_severity: 2
ama_category: Undestandable
ama_category: U
ama_affected_users: Visual
ama_success_criterion: 4.1.2@https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html)
ama_success_criterion: 4.1.2@https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html
---

# Accessibility Label
Expand All @@ -13,7 +13,7 @@ The [accessibilityLabel](https://reactnative.dev/docs/accessibility#accessibilit

<ScreenReader>
<When title="The user focuses the component">
<Then>The Screen Reader reads out the label</Then>
<Then title="The Screen Reader reads out the label" />
</When>
</ScreenReader>

Expand All @@ -34,6 +34,10 @@ This is especially crucial for icon-only buttons, where the control lacks textua
</Pressable>
```

| Voice Over | Talkback | |
| ------------------------------------------ | ------------------------------------------ | -------- |
| Contact us, button, double tap to activate | Contact us, button, double tap to activate | <Good /> |

## No Accessibility Label

### The problem
Expand All @@ -48,13 +52,21 @@ Let's consider the following example:

When testing the button with both VoiceOver and TalkBack, they both read:

> button, Contact us, double-tap to activate
| Voice Over | Talkback | |
| ------------------------------------------ | ------------------------------------------ | --------- |
| button, Contact us, double tap to activate | button, Contact us, double tap to activate | <Wrong /> |

The `accessibilityRole` is announced, and then the inner text is read, if any.

:::caution

Because the component has no `accessibilityLabel`, only the `accessibilityRole` is announced; they read the inner text, if any, and in this case: **Contact us**. Finally, the last part tells the user that the component can be interacted with by performing a double-tap.
While the screen reader's ability to read out text might seem sufficient, it's crucial for the app's accessibility to align with the expectations of the underlying operating system, whether it's iOS or Android. On both platforms, the standard behaviour for screen readers is to announce the label first. Failing to meet this expectation can create an inconsistent and confusing user experience.

:::

<br />

**What's happen if no text is available?**
### Icon only buttons

```jsx
<Pressable onPress={goBack} accessibilityRole="button">
Expand All @@ -64,7 +76,9 @@ Because the component has no `accessibilityLabel`, only the `accessibilityRole`

When testing the button with both VoiceOver and TalkBack, they both read:

> button, double-tap to activate
| Voice Over | Talkback | |
| ------------------------------------------ | ------------------------------------------ | --------- |
| button, Contact us, double tap to activate | button, Contact us, double tap to activate | <Wrong /> |

Here the assistive technology only reads the role and the action that can be performed with the component. So there is a complete lack of helpful information about what we're going to trigger.

Expand Down Expand Up @@ -107,23 +121,21 @@ Screen readers may interpret capital letters as acronyms, misinterpreting conten

This is how the different screen readers handle the uppercase label:

| Voice Over | Talkback |
| ----------------- | --------------- |
| A-D-D to the cart | Add to the cart |
| Voice Over | Talkback | |
| ----------------- | --------------- | --------- |
| A-D-D to the cart | Add to the cart | <Wrong /> |

In this case, VoiceOver does the spelling of the word `ADD` while talkback reads it correctly.
The remaining words are read correctly by both screen readers.

#### Example: `CONTACT US`

| Voice Over | Talkback |
| ------------ | ------------ |
| Contact U.S. | Contact U.S. |
| Voice Over | Talkback | |
| ------------ | ------------ | --------- |
| Contact U.S. | Contact U.S. | <Wrong /> |

The word `CONTACT` is read correctly, but both screen readers spell the word `US` as it is interpreted as `U.S.` for `United States.

A similar issue happens if a sentence contains the word **IT**, for example.

## AMA dev runtime errors <DevOnly />

### NO_ACCESSIBILITY_LABEL <Must />
Expand Down
38 changes: 25 additions & 13 deletions docs/guidelines/accessibility-role.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
# Accessibility Role
---
ama_severity: 1
ama_category: O
ama_affected_users: Visual
ama_success_criterion: 4.1.2@https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html
---

<Severity level="must" />
# Accessibility Role

The [accessibilityRole](https://reactnative.dev/docs/accessibility#accessibilityrole) is required for all interactive components to communicate their purpose to assistive technology users.

## Expectation

<ScreenReader>
<When title="The user focuses the component">
<Then title="The Screen Reader reads out the label">
<And>The Screen Reader reads out the role</And>
</Then>
</When>
</ScreenReader>

When using an accessibility role of **button**, the screen reader automatically announces "double tap to activate" after reading the accessibility label.
Each accessibility role informs the user of the component type and available actions.

Expand All @@ -26,17 +39,16 @@ For those cases AMA automatically uses the correct role for the running platform
</Pressable>
```

## Lack of accessibility role
| VoiceOver | Talkback |
| ------------------------------------------ | ------------------------------------------ |
| Contact us, button, double tap to activate | Contact us, button, double tap to activate |

What's happen if we skip it? The lack of a value causes affects the Screen Reader behaviour:
## Lack of accessibility role

- VoiceOver only reads the component `accessibilityLabel` and `accessibilityHint`, if specified, or any text inside the component
- TalkBack, besides reading the component `accessibilityLabel` and `accessibilityHint`, if specified, or any text inside the component, also adds "double-tap" to activate.
What happens if we skip it? The user will have no or little clue about what happens if they trigger the component:

### Example

Let's consider the following example:

```jsx
<Pressable onPress={doSomething}>Contact us</Pressable>
```
Expand All @@ -52,7 +64,7 @@ VoiceOver users will have no clue that an action can be triggered, while Android

---

### NO_ACCESSIBILITY_ROLE
### NO_ACCESSIBILITY_ROLE <Must />

This error is used when a pressable element has no [accessibilityRole](https://reactnative.dev/docs/accessibility#accessibilityrole) defined.

Expand All @@ -63,7 +75,7 @@ This rule is mandatory and cannot be turned off!

## Related AMA components

- [ExpandablePressable](../components/expandablepressable)
- [Pressable](../components/pressable)
- [TouchableOpacity](../components/touchableopacity)
- [TouchableWithoutFeedback](../components/TouchableWithoutFeedback)
- [ExpandablePressable](/core/components/expandablepressable)
- [Pressable](/core/components/pressable)
- [TouchableOpacity](/core/components/touchableopacity)
- [TouchableWithoutFeedback](/core/components/TouchableWithoutFeedback)
118 changes: 118 additions & 0 deletions docs/guidelines/accessibility-states.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
---
ama_severity: 2
ama_category: U
ama_affected_users: Visual
ama_success_criterion: 4.1.2@https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html
---

# Accessibility States

Accessibility states are specific attributes that can be added to a component to communicate its current status to assistive technology.

## aria-busy

<Serious withLabel />

<br /><br />

Indicates an element is being modified and that assistive technologies may want to wait until the changes are complete before informing the user about the update.[^1]

| Type | Default |
| ------- | ------- |
| boolean | false |

### Expectations

<ScreenReader>
<When title="The user triggers (double tap) a component">
<And title="The component is performing a long (or async) task">
<Then noChildren>The Screen Reader announces the component as <strong>busy</strong></Then>
</And>
</When>
</ScreenReader>

#### Example

Assuming we have a button that adds the given product ID to the cart, which requires an API call:

```tsx
const AddToCart = ({ productID }: { productID: string }) => {
const { addToCart, isAddingToCart } = useQuery(ADD_TO_CART);

const onPress = async () => {
const result = await addToCart();
};

return (
<Pressable
accessibilityLabel="Add to cart"
accessibilityRole="button"
ariaBusy={isAddingToCart}
onPress={isAddingToCart ? undefined : onPress}
>
{isAddingToCart} ? <ActivityIndicator /> : <Text>Add to cart</Text>
</Pressable>
);
};
```

In the example, while the adding action is happening, the button:

- Ignores any press action
- Shows a loading spinner

While this works fine for sighted users, we must add the `ariaBusy={isAddingToCart}` property for visually impaired users.

### Screen Reader behaviour

#### The user double taps on the example component:

| Voice Over | Talkback |
| ---------- | ----------------------------- |
| | plays a sound as confirmation |

#### The user focuses again on the component while the API is still in flight:

| Voice Over | Talkback |
| ---------- | ------------------------------------------------- |
| | Add to cart, busy, button, double tap to activate |

## aria-checked

Indicates the state of a checkable element. This field can either take a boolean or the "mixed" string to represent mixed checkboxes.

| Type | Default |
| ---------------- | ------- |
| boolean, 'mixed' | false |

## aria-disabled

Indicates that the element is perceivable but disabled, so it is not editable or otherwise operable.

| Type | Default |
| ------- | ------- |
| boolean | false |

## aria-expanded

Indicates whether an expandable element is currently expanded or collapsed.

| Type | Default |
| ------- | ------- |
| boolean | false |

## aria-selected

Indicates whether a selectable element is currently selected or not.

| Type | Default |
| ------- | ------- |
| boolean | false |

## External references

- [MDN: aria-busy](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-busy)
- [MDN: aria-checked](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-checked)
- [MDN: aria-disabled](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-disabled)
- [MDN: aria-expanded](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-expanded)
- [MDN: aria-selected](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-selected)
18 changes: 14 additions & 4 deletions docs/guidelines/guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,21 @@ This section contains accessibility best practices for native mobile apps.
The guidelines are based on the w3c recommendations [Accessibility Guideline](https://www.w3.org/TR/WCAG21/) and are intended for use
by anyone building an accessible app with React Native and are not limited to being used with AMA.

The AMA guidelines are labelled with different levels of severity to indicate their importance:
## Severities

- <Critical />: These best practices are mandatory and must be enforced. Failing to implement them will result in an inaccessible mobile app.
- <Serious />: While these issues don't entirely prevent users with assistive technology from accessing the content, they pose significant challenges.
- <Warning />: These best practices are considered "nice to have." Adhering to them enhances the accessibility of your app.
The AMA guidelines are labelled with different levels of severity to indicate their importance.

### <span class="ama-critical">Critical</span>

These best practices are mandatory and must be enforced. Failing to implement them will result in an inaccessible mobile app.

### <span class="ama-serious">Serious</span>

While these issues don't entirely prevent users with assistive technology from accessing the content, they pose significant challenges.

### <span class="ama-warning">Warning</span>

These best practices are considered "nice to have." Adhering to them enhances the accessibility of your app.

## External references

Expand Down
34 changes: 34 additions & 0 deletions docs/guidelines/pour.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
sidebar_position: 1
---

# POUR - Accessibility Principles

## Perceivable

Information and user interface components must be presentable to users in ways they can perceive.

The Perceivable principle includes guidelines for text alternatives, time-based media, adaptable content, and distinguishable content.

## Operable

User interface components and navigation must be operable.

The Operable principle includes guidelines for keyboard accessibility, providing enough time, avoiding seizures and physical reactions, navigation, and input modalities.

## Understandable

Information and the operation of user interface must be understandable.

The Understandable principle includes guidelines for readable content, predictable content, and input assistance.

## Robust

Content must be robust enough that it can be interpreted by a wide variety of user agents, including assistive technologies.

The Robust principle includes guidelines for content that is compatible with current and future user agents.

## External references

- [What Does It Mean for Content to be POUR?](https://www.accessibility.com/blog/what-does-it-mean-for-content-to-be-pour)
- [Web Accessibility: POUR Acronym Explained](https://equalizedigital.com/web-accessibility-p-o-u-r-acronym/)
21 changes: 19 additions & 2 deletions website/src/components/feature.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,27 @@ export const When = props => {
};

export const Then = props => {
const hasChildren = props.children && !props.noChildren;
const icon = hasChildren ? 'ic:round-plus' : 'typcn:tick';

return (
<li className="ama-then">
<Icon icon="typcn:tick" height={12} />
<strong>Then</strong>: {props.children}
<Icon icon={icon} height={12} />
<strong>Then</strong>: {props.title}
{hasChildren ? <ul>{props.children}</ul> : null}
{props.children}
</li>
);
};

export const And = props => {
const icon = props.children ? 'ic:round-plus' : 'typcn:tick';

return (
<li className="ama-and">
<Icon icon={icon} height={12} />
<strong>And</strong>: {props.title}
{props.children ? <ul>{props.children}</ul> : null}
</li>
);
};
Loading

0 comments on commit a41f9b1

Please sign in to comment.