Skip to content

Commit c0e34eb

Browse files
committed
initial commit
0 parents  commit c0e34eb

16 files changed

+2443
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules/
2+
cache/

.vitepress/config.mts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { defineConfig } from "vitepress";
2+
3+
// https://vitepress.dev/reference/site-config
4+
export default defineConfig({
5+
title: "A11Y For React Devs",
6+
description: "A VitePress Site",
7+
themeConfig: {
8+
sidebar: [
9+
{
10+
items: [
11+
{ text: "WAI-ARIA", link: "/wai-aria" },
12+
{ text: "Semantic HTML", link: "/semantic-html" },
13+
{ text: "Accessible Form", link: "/accessible-forms" },
14+
{ text: "Focus Control", link: "/focus-control" },
15+
{
16+
text: "Mouse and Pointer Events",
17+
link: "/mouse-and-pointer-events",
18+
},
19+
{ text: "Complex Widgets", link: "/complex-widgets" },
20+
{ text: "Development Checklists", link: "/dev-checklists" },
21+
{ text: "Tools", link: "/tools" },
22+
],
23+
},
24+
],
25+
socialLinks: [
26+
{ icon: "github", link: "https://github.com/code-with-amirhossein" },
27+
],
28+
},
29+
});

.vitepress/theme/custom.css

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
:root {
2+
--vp-c-bg: #ffffff;
3+
--vp-c-text: #000000;
4+
--vp-c-bg-alt: #f5f5f5;
5+
}
6+
7+
.dark {
8+
--vp-c-bg: #000000;
9+
--vp-c-text: #ffffff;
10+
--vp-c-bg-alt: #121212;
11+
}
12+
13+
#author {
14+
display: flex;
15+
align-items: center;
16+
}
17+
#author img {
18+
width: 50px;
19+
height: 50px;
20+
border-radius: 50%;
21+
background: #ffffff;
22+
}
23+
#author .author-name {
24+
display: flex;
25+
flex-direction: column;
26+
align-items: flex-start;
27+
margin-left: 10px;
28+
font-size: 1rem;
29+
line-height: 1.2;
30+
}

.vitepress/theme/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import DefaultTheme from "vitepress/theme";
2+
import "./custom.css";
3+
import "@tapsioss/theme";
4+
5+
export default DefaultTheme;

accessible-forms.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
---
2+
outline: "deep"
3+
---
4+
5+
# Accessible Forms
6+
7+
## Labeling
8+
9+
Every HTML form control, such as `<input>` and `<textarea>`, needs to be labeled accessibly. We need to provide descriptive labels that are also exposed to screen readers.
10+
11+
The following resources show us how to do this:
12+
13+
- [The W3C shows us how to label elements](https://www.w3.org/WAI/tutorials/forms/labels/)
14+
- [WebAIM shows us how to label elements](https://webaim.org/techniques/forms/controls)
15+
- [The Paciello Group explains accessible names](https://www.paciellogroup.com/blog/2017/04/what-is-an-accessible-name/)
16+
17+
Although these standard HTML practices can be directly used in React, note that the `for` attribute is written as `htmlFor` in JSX.
18+
19+
::: info
20+
21+
Typically, you will place every `<input>` inside a [`<label>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label) tag. This tells the browser that this label is associated with that input. When the user clicks the label, the browser will automatically focus the input. It’s also essential for accessibility: a screen reader will announce the label caption when the user focuses the associated input.
22+
If you can’t nest `<input>` into a `<label>`, associate them by passing the same ID to `<input id>` and [`<label htmlFor>`.](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/htmlFor) To avoid conflicts between multiple instances of one component, generate such an ID with [`useId`](https://react.dev/reference/react/useId).
23+
24+
<!-- mention this is for react 18 and newer versions -->
25+
26+
```tsx
27+
import { useId } from "react";
28+
29+
export default function Form() {
30+
const ageInputId = useId();
31+
return (
32+
<>
33+
<label>
34+
Your first name:
35+
<input name="firstName" />
36+
</label>
37+
<hr />
38+
<label htmlFor={ageInputId}>Your age:</label>
39+
<input id={ageInputId} name="age" type="number" />
40+
</>
41+
);
42+
}
43+
```
44+
45+
<!-- mention same approach is available for select, textarea and other inputs -->
46+
47+
:::
48+
49+
## Notifying the user of errors
50+
51+
Error situations need to be understood by all users. The following link shows us how to expose error texts to screen readers as well:
52+
53+
- [The W3C demonstrates user notifications](https://www.w3.org/WAI/tutorials/forms/notifications/)
54+
- [WebAIM looks at form validation](https://webaim.org/techniques/formvalidation/)

complex-widgets.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
outline: "deep"
3+
---
4+
5+
# More Complex Widgets
6+
7+
A more complex user experience should not mean a less accessible one. Whereas accessibility is most easily achieved by coding as close to HTML as possible, even the most complex widget can be coded accessibly.
8+
9+
Here we require knowledge of [ARIA Roles](https://www.w3.org/TR/wai-aria/#roles) as well as [ARIA States and Properties](https://www.w3.org/TR/wai-aria/#states_and_properties). These are toolboxes filled with HTML attributes that are fully supported in JSX and enable us to construct fully accessible, highly functional React components.
10+
11+
Each type of widget has a specific design pattern and is expected to function in a certain way by users and user agents alike:
12+
13+
- [ARIA Authoring Practices Guide (APG) - Design Patterns and Examples](https://www.w3.org/WAI/ARIA/apg/patterns/)
14+
- [Heydon Pickering - ARIA Examples](https://heydonworks.com/article/practical-aria-examples/)
15+
- [Inclusive Components](https://inclusive-components.design/)

dev-checklists.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
outline: "deep"
3+
---
4+
5+
# Development Checklists
6+
7+
There are a number of tools we can use to assist in the creation of accessible web applications.
8+
9+
## Keyboard Navigation
10+
11+
By far the easiest and also one of the most important checks is to test if your entire website can be reached and used with the keyboard alone. Do this by:
12+
13+
1. Disconnecting your mouse.
14+
2. Using `Tab` and `Shift+Tab` to browse.
15+
3. Using `Enter` to activate elements.
16+
4. Where required, using your keyboard arrow keys to interact with some elements, such as menus and dropdowns.
17+
18+
## Increase text size to 200%!
19+
20+
Is the content still readable? Does increasing the text size cause content to overlap?
21+
22+
## Straw Testing
23+
24+
Proximity issues can arise when interface elements are designed far apart from one another. This mostly affects people with **low-vision** who rely on zoom software.
25+
26+
What happens when someone uses zoom software is that they only see a small fraction of the screen at once. Usually, the zoomed portion of the screen follows the current position of the mouse pointer or keyboard cursor.
27+
28+
As a result of someone only being able to see a small section at a time, oftentimes when attempting to complete a task, content is difficult to find or may be missed entirely.
29+
30+
How do we test to ensure there are minimal to no proximity issues with our design? One relatively simple and effective method is to perform what's called, "the straw test."
31+
32+
<iframe height="500" style="width: 100%;" scrolling="no" title="Poor Proximity" src="//codepen.io/svinkle/embed/wXNMZr/?height=265&amp;theme-id=0&amp;default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true">
33+
See the Pen <a href="https://codepen.io/svinkle/pen/wXNMZr/">Poor Proximity</a> by Scott Vinkle
34+
(<a href="https://codepen.io/svinkle">@svinkle</a>) on <a href="https://codepen.io">CodePen</a>.
35+
</iframe>
36+
37+
<iframe height="500" style="width: 100%;" scrolling="no" title="Better Proximity" src="//codepen.io/svinkle/embed/LrqNPV/?height=265&amp;theme-id=0&amp;default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true">
38+
See the Pen <a href="https://codepen.io/svinkle/pen/LrqNPV/">Better Proximity</a> by Scott Vinkle
39+
(<a href="https://codepen.io/svinkle">@svinkle</a>) on <a href="https://codepen.io">CodePen</a>.
40+
</iframe>

focus-control.md

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
---
2+
outline: "deep"
3+
---
4+
5+
<script setup>
6+
import { registerAll } from '@tapsioss/web-components';
7+
registerAll();
8+
</script>
9+
10+
# Focus Control
11+
12+
Ensure that your web application can be fully operated with the keyboard only:
13+
14+
- [WebAIM talks about keyboard accessibility](https://webaim.org/techniques/keyboard/)
15+
16+
## Keyboard focus and focus outline
17+
18+
Keyboard focus refers to the current element in the DOM that is selected to accept input from the keyboard. We see it everywhere as a focus outline similar to that shown in the following image:
19+
20+
[![Blue keyboard focus outline around a selected link.](https://legacy.reactjs.org/static/dec0e6bcc1f882baf76ebc860d4f04e5/4fcfe/keyboard-focus.png)](https://legacy.reactjs.org/static/dec0e6bcc1f882baf76ebc860d4f04e5/4fcfe/keyboard-focus.png)
21+
22+
Only ever use CSS that removes this outline, for example by setting `outline: 0`, if you are replacing it with another focus outline implementation.
23+
24+
<section aria-hidden="true" style="background: white; border-radius: 8px; padding: 12px; display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 8px;">
25+
26+
<tapsi-button variant="brand">عنوان دکمه</tapsi-button>
27+
<tapsi-rate-slider label="rate-slider"></tapsi-rate-slider>
28+
<tapsi-radio label="radio"></tapsi-radio>
29+
<tapsi-switch label="switch"></tapsi-switch>
30+
<tapsi-checkbox label="checkbox"></tapsi-checkbox>
31+
32+
</section>
33+
34+
## Mechanisms to skip to desired content
35+
36+
Provide a mechanism to allow users to skip past navigation sections in your application as this assists and speeds up keyboard navigation.
37+
38+
### Skip Links
39+
40+
On most pages, keyboard and screen reader users must navigate a long list of navigation links and other elements before ever arriving at the main content. This can be particularly difficult for users with some forms of motor disabilities. Consider users with no or limited arm movement who navigate a web page by tapping their heads on a switch or that use a stick in their mouth to press keyboard keys. Requiring users to perform any action numerous times before reaching the main content poses an accessibility barrier.
41+
42+
Of course, sighted people who use their mouse do not have any trouble with web pages like this. They can almost immediately scan over the page and identify where the main content is. Skip navigation links are useful to give screen reader and keyboard users the same capability of navigating directly to the main content.
43+
44+
The idea is simple enough: provide a link at the top of the page that, when activated, jumps the user to the beginning of the main content area.
45+
46+
```html
47+
<body>
48+
<a href="#main">Skip to main content</a>
49+
<nav role="navigation">
50+
<ul>
51+
<li><a href="/">Home</a></li>
52+
<li><a href="/about">About</a></li>
53+
<li><a href="/blog">Blog</a></li>
54+
</ul>
55+
</nav>
56+
<main id="main">
57+
<!-- page specific content -->
58+
</main>
59+
</body>
60+
```
61+
62+
### Landmark Elements
63+
64+
Check [Semantic HTML: Landmark Elements](/semantic-html#landmark-elements)
65+
66+
## Programmatically managing focus
67+
68+
Our React applications continuously modify the HTML DOM during runtime, sometimes leading to keyboard focus being lost or set to an unexpected element. In order to repair this, we need to programmatically nudge the keyboard focus in the right direction. For example, by resetting keyboard focus to a button that opened a modal window after that modal window is closed.
69+
70+
MDN Web Docs takes a look at this and describes how we can build [keyboard-navigable JavaScript widgets](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Keyboard-navigable_JavaScript_widgets).
71+
72+
To set focus in React, we can use [Refs to DOM elements](https://legacy.reactjs.org/docs/refs-and-the-dom.html).
73+
74+
Using this, we first create a ref to an element in the JSX of a component class:
75+
76+
```tsx
77+
class CustomTextInput extends React.Component {
78+
constructor(props) {
79+
super(props);
80+
// Create a ref to store the textInput DOM element this.textInput = React.createRef(); }
81+
render() {
82+
// Use the `ref` callback to store a reference to the text input DOM // element in an instance field (for example, this.textInput). return (
83+
<input
84+
type="text"
85+
ref={this.textInput} />
86+
);
87+
}
88+
}
89+
```
90+
91+
Then we can focus it elsewhere in our component when needed:
92+
93+
```tsx
94+
focus() {
95+
// Explicitly focus the text input using the raw DOM API
96+
// Note: we're accessing "current" to get the DOM node
97+
this.textInput.current.focus();
98+
}
99+
```
100+
101+
Sometimes a parent component needs to set focus to an element in a child component. We can do this by [exposing DOM refs to parent components](https://legacy.reactjs.org/docs/refs-and-the-dom.html#exposing-dom-refs-to-parent-components) through a special prop on the child component that forwards the parent’s ref to the child’s DOM node.
102+
103+
```tsx
104+
function CustomTextInput(props) {
105+
return (
106+
<div>
107+
<input ref={props.inputRef} />{" "}
108+
</div>
109+
);
110+
}
111+
112+
class Parent extends React.Component {
113+
constructor(props) {
114+
super(props);
115+
this.inputElement = React.createRef();
116+
}
117+
render() {
118+
return <CustomTextInput inputRef={this.inputElement} />;
119+
}
120+
}
121+
122+
// Now you can set focus when required.
123+
this.inputElement.current.focus();
124+
```
125+
126+
When using a [HOC](https://legacy.reactjs.org/docs/higher-order-components.html) to extend components, it is recommended to [forward the ref](https://legacy.reactjs.org/docs/forwarding-refs.html) to the wrapped component using the `forwardRef` function of React. If a third party HOC does not implement ref forwarding, the above pattern can still be used as a fallback.
127+
128+
A great focus management example is the [react-aria-modal](https://github.com/davidtheclark/react-aria-modal). This is a relatively rare example of a fully accessible modal window. Not only does it set initial focus on the cancel button (preventing the keyboard user from accidentally activating the success action) and trap keyboard focus inside the modal, it also resets focus back to the element that initially triggered the modal.
129+
130+
::: warning
131+
While this is a very important accessibility feature, it is also a technique that should be used judiciously. Use it to repair the keyboard focus flow when it is disturbed, not to try and anticipate how users want to use applications.
132+
:::

index.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
# https://vitepress.dev/reference/default-theme-home-page
3+
layout: home
4+
5+
hero:
6+
name: "Accessibility"
7+
text: "for React Developers"
8+
tagline: <a href="https://github.com/amir78729"><div id="author"><img src="https://avatars.githubusercontent.com/u/44297246?v=4" alt="profile picture" /> <div class="author-name"><span>Amirhossein</span><span>Alibakhshi</span></div></div></a>
9+
actions:
10+
- theme: brand
11+
text: Get Started!
12+
link: /wai-aria
13+
---

0 commit comments

Comments
 (0)