Require to have a non-empty
alt
prop, or role="presentation"
✅ Enabled (error)
// Bad
/*
function Foo(src) {
return <img src={src} />;
}
*/
// Good
function Foo({ alt, src }) {
return <img alt={alt} src={src} />;
}
Enforce all aria-* props are valid.
✅ Enabled (error)
// Bad
/*
<div id="address_label">Enter your address</div>;
<input aria-labeledby="address_label" />;
*/
// Good
<div id="address_label">Enter your address</div>;
<input aria-labelledby="address_label" />;
Enforce ARIA state and property values are valid.
✅ Enabled (error)
// Bad
/*
<span aria-hidden="yes">foo</span>;
*/
// Good
<span aria-hidden="true">foo</span>;
Require ARIA roles to be valid and non-abstract
✅ Enabled (error)
// Bad
/*
<div role="datepicker"></div>;
<div role="range"></div>;
<div role=""></div>;
*/
// Good
<div role="button"></div>;
<div role={role}></div>;
<div></div>;
Enforce that elements that do not support ARIA roles, states, and properties do not have those attributes.
✅ Enabled (error)
// Bad
/*
<meta aria-hidden="false" charSet="UTF-8" />;
*/
// Good
<meta charSet="UTF-8" />;
disallow href "#"
❌ Disabled
// Bad
<a href="#" />;
<a href={"#"} />;
<a href={`#`} />;
// Good
<a href="https://github.com" />;
<a href="#section" />;
<a href="foo" />;
<a href={undefined} />;
Prevent img alt text from containing redundant words like "image", "picture", or "photo"
✅ Enabled (error)
// Bad
/*
<img alt="Photo of foo being weird." src="foo" />;
<img alt="Image of me at a bar!" src="bar" />;
<img alt="Picture of baz fixing a bug." src="baz" />;
*/
// Good
<img alt="Foo eating a sandwich." src="foo" />;
<img
aria-hidden
alt="Picture of me taking a photo of an image"
src="bar"
/>;
<img alt={`Baz taking a ${photo}`} src="baz" />;
require that JSX labels use "htmlFor"
❌ Disabled
// Bad
/*
function Foo(props) {
return <label {...props} />;
}
*/
// Good
function Foo({ htmlFor, props }) {
return <label htmlFor={htmlFor} {...props} />;
}
require that mouseover/out come with focus/blur, for keyboard-only users
❌ Disabled
// Bad
<div onMouseOver={() => {}} />;
<div onMouseOut={() => {}} />;
<div onMouseOver={() => {}} />;
<div onMouseOut={() => {}} />;
// Good
<div onMouseOver={() => {}} onFocus={() => {}} />;
<div onMouseOut={() => {}} onBlur={() => {}} />;
<div onMouseOver={() => {}} onFocus={() => {}} />;
<div onMouseOut={() => {}} onBlur={() => {}} />;
Prevent use of
accessKey
✅ Enabled (error)
// Bad
/*
<div accessKey="h" />;
*/
// Good
<div />;
require onBlur instead of onChange
❌ Disabled
// Bad
<select onChange={updateModel} />;
// Good
(
<select onBlur={updateModel}>
<option />
</select>
);
(
<select>
<option onBlur={handleOnBlur} onChange={handleOnChange} />
</select>
);
Enforce that elements with onClick handlers must be focusable.
❌ Disabled
// Bad
<span onClick="submitForm();">Submit</span>;
<a onClick="showNextPage();">Next page</a>;
// Good
<div aria-hidden onClick={() => {}} />;
<span onClick="doSomething();" tabIndex="0">Click me!</span>;
<span onClick="doSomething();" tabIndex="-1">Click me too!</span>;
<button onClick="doSomething();">Click the button :)</button>;
require things with onClick to have an aria role
❌ Disabled
// Bad
<div onClick={() => {}} />;
<div onClick={() => {}} {...props} />;
<div onClick={() => {}} aria-hidden={false} />;
<a onClick={() => {}} />;
// Good
<div onClick={() => {}} role="button" />;
// Interactive element does not require role.
<input type="text" onClick={() => {}} />;
// tabIndex makes this interactive.
<a tabIndex="0" onClick={() => {}} />;
// button is interactive.
<button onClick={() => {}} className="foo" />;
// This is hidden from screenreader.
<div
onClick={() => {}}
role="button"
aria-hidden
/>;
// This is a higher-level DOM component
<Input onClick={() => {}} type="hidden" />;
Enforce that elements with ARIA roles must have all required attributes for that role.
✅ Enabled (error)
// Bad
/*
<span
role="checkbox"
aria-labelledby="foo"
tabIndex="0"
>
</span>;
*/
// Good
<span
role="checkbox"
aria-checked="false"
aria-labelledby="foo"
tabIndex="0"
>
</span>;
Enforce that elements with explicit or implicit roles defined contain only aria-* properties supported by that role.
✅ Enabled (error)
// Bad
/*
(
<ul role="radiogroup" aria-labelledby="foo">
<li aria-required tabIndex="-1" role="radio" aria-checked="false">Rainbow Trout</li>
<li aria-required tabIndex="-1" role="radio" aria-checked="false">Brook Trout</li>
<li aria-required tabIndex="0" role="radio" aria-checked="true">Lake Trout</li>
</ul>
);
*/
// Good
(
<ul role="radiogroup" aria-required aria-labelledby="foo">
<li tabIndex="-1" role="radio" aria-checked="false">Rainbow Trout</li>
<li tabIndex="-1" role="radio" aria-checked="false">Brook Trout</li>
<li tabIndex="0" role="radio" aria-checked="true">Lake Trout</li>
</ul>
);
Enforce tabIndex value is not greater than zero.
❌ Disabled
// Bad
<span tabIndex="5">foo</span>;
<span tabIndex="3">bar</span>;
<span tabIndex="1">baz</span>;
<span tabIndex="2">never really sure what goes after baz</span>;
// Good
<span tabIndex="0">foo</span>;
<span tabIndex="-1">bar</span>;
<span tabIndex={0}>baz</span>;