Acessibilidade
Por que Acessibilidade?
A acessibilidade da Web (também chamada de ** a11y **) é o design e a criação de sites que podem ser usados por todos. O suporte à acessibilidade é necessário para permitir que tecnologias assistivas interpretem as páginas da web.
React suporta totalmente a construção de sites acessíveis, muitas vezes usando técnicas HTML padrão.
Padrões e Diretrizes
WCAG
O Web Content Accessibility Guidelines fornece diretrizes para a criação de sites acessíveis.
As seguintes checklists das WCAG fornecem uma visão geral:
WAI-ARIA
O documento Web Accessibility Initiative - Accessible Rich Internet Applications contém técnicas para a criação de widgets JavaScript totalmente acessíveis.
Note que todos os atributos HTML aria-* são totalmente suportados no JSX. Enquanto a maioria das propriedades e atributos do DOM no React são camelCase, esses atributos devem ser hyphen-case (também conhecidos como kebab-case, lisp-case, etc), pois estão em HTML:
<input
type="text"
aria-label={labelText} aria-required="true" onChange={onchangeHandler}
value={inputValue}
name="name"
/>Linguagem HTML
Linguagem é a base da acessibilidade em um aplicativo da web. Usando os elementos HTML corretamente para reforçar o significado da informação em nossos sites, muitas vezes a acessibilidade pode vir gratuitamente.
Às vezes, quebramos a semântica de HTML quando adicionamos elementos <div> ao nosso JSX somente para fazer nosso código React funcionar, especialmente ao trabalhar com listas (<ol>, <ul> e <dl>) e HTML <table>. Nesses casos, devemos usar React Fragments para agrupar vários elementos.
Por exemplo,
import React, { Fragment } from 'react';
function ListaDeItems({ item }) {
return (
<Fragment> <dt>{item.nome}</dt>
<dd>{item.descricao}</dd>
</Fragment> );
}
function Glossario(props) {
return (
<dl>
{props.items.map(item => (
<ListaDeItems item={item} key={item.id} />
))}
</dl>
);
}Você pode mapear uma coleção de items para uma matriz de fragmentos como faria com qualquer outro tipo de elemento:
function Glossario(props) {
return (
<dl>
{props.items.map(item => (
// Fragments também aceitam `key`(chave) prop quando estão mapeando coleções
<Fragment key={item.id}> <dt>{item.nome}</dt>
<dd>{item.descricao}</dd>
</Fragment> ))}
</dl>
);
}Quando você não precisa de nenhum prop na tag Fragment você pode usar a syntax curta, se a sua configuração suportar:
function ListaDeItems({ item }) {
return (
<> <dt>{item.nome}</dt>
<dd>{item.descricao}</dd>
</> );
}Para mais informações, veja a documentação para Fragments.
Formulários Acessíveis
Rótulos
Todos os elements de um formulário HTML, como <input> e <textarea>, precisam ser rotulados. Precisamos fornecer rótulos descritivos pois são expostos aos leitores de tela.
Os seguintes artigos nos mostram como fazer isso:
- The W3C shows us how to label elements
- WebAIM shows us how to label elements
- The Paciello Group explains accessible names
Embora essas práticas HTML padrão possam ser usadas diretamente em React, observe que o atributo for está escrito como htmlFor em JSX:
<label htmlFor="nomeDaEntrada">Nome:</label><input id="nomeDaEntrada" type="text" name="nome"/>Notificando erros ao usuário
Situações de erro precisam ser entendidas por todos os usuários. Os artigos a seguir nos mostram como expor os erros aos leitores de tela:
Controle de Foco
Certifique-se de que seu aplicativo da web seja totalmente navegável apenas com o teclado:
Foco no teclado e foco de contorno
Foco no teclado se refere ao elemento no DOM que foi selecionado e aceita ações do teclado. Podemos ver o contorno do foco na imagem a seguir:
Somente use CSS que elimine este contorno, por exemplo, definindo outline: 0, se você for substituí-lo por outra implementação de esquema de foco.
Mecanismos para pular conteúdo
São mecanismos para permitir que os usuários ignorem as seções de navegação anteriores em seu aplicativo, pois isso ajuda e acelera a navegação pelo teclado.
Skiplinks ou Links para Pular Navegação são links de navegação ocultos que só se tornam visíveis quando os usuários interagem com a página usando o teclado. Eles são muito fáceis de implementar com alguns estilos e âncoras de páginas:
Também use elementos e pontos de referência, como <main> e <aside>, para demarcar regiões de páginas como tecnologia assistiva, permitindo que o usuário navegue rapidamente para estas seções.
Leia mais sobre o uso desses elementos para melhorar a acessibilidade aqui:
Programaticamente gerenciando o foco
Aplicações em React modificam continuamente o HTML DOM durante o tempo de execução, às vezes levando à perda de foco do teclado ou a um elemento inesperado. Para consertar isso, precisamos programar o foco do teclado na direção certa, de maneira programática. Por exemplo, redefinindo o foco do teclado para um botão que abriu uma janela modal depois que essa janela restrita é fechada.
Você pode encontrar mais informações de como fazer isto no MDN navegação por teclado de JavaScript widgets.
Para definir o foco no React, podemos usar Refs para elementos no DOM.
Dessa maneira, primeiro criamos uma referência a um elemento no JSX de uma classe de componente:
class EntradaDeTexto extends React.Component {
constructor(props) {
super(props);
// Cria um ref para guardar o inputDeTexto no DOM this.inputDeTexto = React.createRef(); }
render() {
// Use a `ref` callback para guardar a referencia do texto no input dentro do DOM // elemento em um campo (por exemplo, this.inputDeTexto). return (
<input
type="text"
ref={this.inputDeTexto} />
);
}
}Então podemos nos concentrar em outro lugar em nosso componente quando necessário:
focus() {
// Focalize explicitamente a entrada de texto usando a API DOM
// Nota: estamos acessando o DOM "atual" para obter o elemento
this.textInput.current.focus();
}Às vezes, um componente pai precisa definir o foco para um elemento em um componente filho. Nós podemos fazer isso expondo as referências DOM aos componentes pais, através de um prop especial no componente filho que encaminha a referência do pai o elemento filho.
function EntradaDeTexto(props) {
return (
<div>
<input ref={props.inputRef} /> </div>
);
}
class ComponentePai extends React.Component {
constructor(props) {
super(props);
this.inputElement = React.createRef(); }
render() {
return (
<EntradaDeTexto inputRef={this.inputElement} /> );
}
}
// Agora você pode definir o foco quando necessário.
this.inputElement.current.focus();Ao usar um HOC(Componente de alta ordem) para estender componentes é recomendado encaminhar a ref para o componente de menor order usando a função de React forwardRef. Se um terceiro HOC não passar a referência, o padrão acima ainda pode ser usado como fallback.
Um ótimo exemplo de gerenciamento de foco é o react-aria-modal. Este é um exemplo relativamente raro de uma janela modal totalmente acessível. Não só define o foco inicial o botão cancelar (impedindo o usuário do teclado de ativar acidentalmente a ação de sucesso) e interceptar o foco do teclado dentro do modal, ele também redefine o foco de volta para o elemento que inicialmente acionou o modal.
Nota:
Embora esse seja um recurso de acessibilidade muito importante, também é uma técnica que deve ser usada de maneira criteriosa. Use-o para reparar o comportamento do foco do teclado quando ele é alterado, e não para tentar antecipar como os usuários desejam usar os aplicativos.
Movimentos do mouse e ponteiro (cursor)
Certifique-se de que todas as funcionalidades expostas através do movimento de mouse ou ponteiro também possam ser acessadas usando apenas o teclado. Se depender apenas do movimento do mouse, haverá muitos casos em que usuários de teclado não poderão usar seu aplicativo.
Para ilustrar isso, abaixo pode-se ver um exemplo clássico de quebra da acessibilidade causada por cliques. Esse é o padrão de clique externo, em que um usuário pode desativar um popover aberto clicando fora do elemento.
Isso geralmente é implementado ao anexar um click ao objeto de janela que fecha o popover:
class ClickForaExemplo extends React.Component {
constructor(props) {
super(props);
this.state = { isOpen: false };
this.toggleContainer = React.createRef();
this.onClickHandler =