Enter The Dragon (Drop): Reordenação da Lista Acessível
Publicados: 2022-03-10Ao longo dos anos como desenvolvedor web com foco em acessibilidade, lidei principalmente com componentes de interface do usuário padronizados e amplamente adotados, bem suportados por tecnologias assistivas (AT). Para esses tipos de widgets, existem práticas concisas de autoria de ARIA, bem como ótimas ferramentas, como o axe-core, que podem ser usadas para testar componentes da Web quanto a problemas de acessibilidade. Criar widgets menos comuns, especialmente aqueles que não possuem convenções amplamente adotadas para interação do usuário, pode ser muito complicado.
Um dos desafios mais difíceis que encontrei é a lista reordenada de arrastar e soltar. Embora uma lista reordenável seja um widget um tanto comumente usado com convenções intuitivas para usuários de mouse, não está claro como os usuários de tecnologia assistiva somente de teclado podem realizar essa tarefa simples. Devido à ausência de atributos ARIA suportados, o Dragon Drop utiliza regiões ao vivo para transmitir as informações necessárias para todos os usuários reordenarem uma lista.
Regiões ao vivo
As regiões ao vivo são elementos HTML equipados com atributos ARIA que podem ser usados para notificar os leitores de tela sobre alterações de conteúdo. Eles nos permitem fornecer um anúncio de leitor de tela completamente personalizado sem ter que mudar o foco! As regiões ao vivo são ótimas para atualizações em tempo real em partes remotas da página, atualizações de status e informações sensíveis ao tempo.
Eles são comumente usados em logs de bate-papo, indicadores de progresso, atualizações de resultados esportivos e alertas meteorológicos, mas devem ser usados com moderação, pois podem criar facilmente uma experiência excessivamente detalhada para usuários de leitores de tela. Se você é novo nas regiões ao vivo ou apenas deseja explorar o que elas podem fazer, confira meu playground da região ao vivo, que permite configurar sua própria região ao vivo personalizada.
Se você quiser usar regiões ao vivo em seu aplicativo, consulte o módulo Live Region no npm.
<div aria-live="assertive" role="log" aria-relevant="additions" aria-atomic="true"></div>
Por que usar regiões dinâmicas?
Em um mundo ideal, eu poderia simplesmente confiar nos atributos ARIA de arrastar e soltar aria-grabbed
e aria-dropeffect
. No entanto, na realidade, o suporte para esses atributos é raro e, quando suportado, a experiência é confusa e contraintuitiva para usuários de leitores de tela. Além disso, esses dois atributos foram descontinuados desde o ARIA 1.1, o que significa que não veremos o suporte para esses atributos crescer no futuro.
A conversa do W3C sobre essa descontinuação pode ser encontrada aqui. Por causa desses problemas, decidi não usar o efeito aria-grabbed
e aria-dropeffect
no Dragon Drop. O suporte variado para atributos ARIA dentro da vasta gama de emparelhamentos de tecnologia assistiva/navegador é bastante prevalente no mundo da acessibilidade. Felizmente, atributos de região ao vivo como role
, aria-live
, aria-relevant
e aria-atomic
são amplamente suportados por leitores de tela como JAWS, NVDA e VoiceOver.
Acessibilidade otimizada
Dragon Drop é um módulo de reordenação de lista altamente configurável que funciona para usuários de mouse, teclado e tecnologia assistiva. Alguns anos atrás, quando decidi escrevê-lo, listas de reordenação acessíveis foram trazidas várias vezes em projetos nos quais eu estava trabalhando, mas ainda não tinha visto uma solução funcional. Das dezenas de plugins de reordenação de listas de arrastar e soltar que encontrei, a maioria deles não foi projetada com acessibilidade em mente e, como resultado, eram muito inacessíveis.
Dragon Drop foi testado com VoiceOver, JAWS e NVDA e permite que usuários AT reorganizem uma lista com sucesso.
Eu me propus a responder a todas as perguntas que qualquer usuário possa ter ao encontrar uma lista reordenável. Essas perguntas foram respondidas para usuários de mouse com visão por meio de convenções comuns, mas e o resto dos usuários?
Como posso pegar um item?
Ao fornecer um controle que transmite o estado capturado de um item, juntamente com algum texto de ajuda de nível superior, podemos responder a essa pergunta. Por exemplo, um controle com o texto acessível (reunido por AT através de seu nome, função e valor) “Reordenar Item 1, botão de alternância” informa ao usuário que é um botão que, quando ativado, pegará o item e iniciará um reordenação.
Dragon drop usa o atributo aria-pressed
para informar aos usuários AT quando um item está sendo “arrastado” e quando não está. Ele pode ser configurado para permitir que um item inteiro seja arrastável, ou apenas um “drag handle” filho, que em ambos os casos a presença do role="button"
e tabindex="0"
é garantida.
Quando um item de arrastar é ativado, aria-pressed="true"
é aplicado ao elemento e um anúncio configurável, como "Item 1 capturado" é lido para leitores de tela por meio da região ao vivo.
Como posso mover um item?
Utilizando aria-describedby
para associar os controles a um texto de ajuda útil, como “Ative o botão de reordenação e use as teclas de seta para reordenar a lista ou use o mouse para arrastar/reordenar”. informa ao usuário como proceder para reordenar. Isso permite que os usuários de leitores de tela saibam que quando um item é pressionado, as teclas de seta para cima e para baixo movem o item para cima e para baixo na lista, respectivamente.
Como posso soltar um item?
Como o atributo aria-pressed
é usado, os usuários podem dizer facilmente como soltar um item. De alguma forma, forma ou formato, todos os leitores de tela mais usados transmitem o estado pressionado de um botão de alternância. O atributo aria-pressed é definido como “false” quando um item é descartado e um anúncio personalizado como “Item 1 descartado” é lido para leitores de tela.
Como posso saber quando a lista foi reordenada?
Sempre que as teclas de seta para cima e para baixo são usadas para alterar a ordem da lista, precisamos garantir que todos os usuários sejam notificados dessa alteração. Para usuários sem visão, devemos mais uma vez confiar nas regiões ao vivo. Um anúncio configurável como “A lista foi reordenada, o item 1 agora é o 4º na lista”. , é lido para transmitir o estado atualizado da lista reordenada. Isso é importante porque os usuários com visão têm feedback visual imediato da ordem alterada e essa mesma informação precisa ser transmitida aos usuários de TA.

Como faço para cancelar a reordenação?
Como não podemos confiar em uma convenção amplamente adotada para tal interação, podemos simplesmente incluir instruções como “Pressione escape para cancelar a reordenação” no texto de ajuda. Além disso, utilizamos a região ativa para fornecer uma leitura personalizada que notifica o usuário sobre o cancelamento.
Interação do teclado
Chave | Comportamento |
---|---|
Entre ou Espaço | Alterna o item entre os estados "agarrado" e "descartado" |
"↓" | Move um item "agarrado" para baixo na lista |
"↑" | Move um item "agarrado" para cima na lista |
Esc | Cancela a reordenação e restaura o pedido inicial |
Vendo o dragão em ação
Confira a demonstração do Dragon Drop na qual você experimenta algumas configurações diferentes.

Colocando Dragon Drop em seu aplicativo
Dragon Drop converte sua lista comum em uma lista reordenável de arrastar e soltar totalmente acessível:
<ul> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </ul> <script> const dragon = document.getElementById('dragon'); // Enter the dragon new DragonDrop(dragon); </script>
Instalação
Dragon Drop é um projeto de código aberto (Licença MIT) e pode ser instalado via npm:
$ npm install drag-on-drop
Pode ser usado com módulos como browserify ou webpack:
// if you're not down with ES6, you can require('drag-on-drop') import DragonDrop from 'drag-on-drop';
Dragon Drop também pode ser facilmente colocado em sua página com o CDN unpkg:
<script source="https://unpkg.com/drag-on-drop"></script> <script> var dragonDrop = new DragonDrop(listElement); </script>
Configuração
Para oferecer suporte a uma ampla variedade de casos de uso, o Dragon Drop é muito configurável.
Abaixo está a configuração padrão:
{ item: 'li', handle: 'button', activeClass: 'dragon-active', inactiveClass: 'dragon-inactive', announcement: { grabbed: el => `Item ${el.innerText} grabbed`, dropped: el => `Item ${el.innerText} dropped`, reorder: (el, items) => { const pos = items.indexOf(el) + 1; const text = el.innerText; return `The list has been reordered, ${text} is now item ${pos} of ${items.length}`; }, cancel: 'Reordering cancelled' } }
Anúncios
A opção de configuração de “anúncio” do Dragon Drop é a mais importante porque é a espinha dorsal da experiência do leitor de tela que o Dragon Drop oferece. É um objeto que contém as funções "grabbed"
, "dropped"
, "reorder"
e "cancel"
permitindo anúncios de região ao vivo personalizados para todas as interações que ocorrem.
Cada uma dessas funções deve retornar uma string de texto de anúncio que é adicionada à região ativa quando a ação determinada ocorre. Um benefício adicional de utilizar essas funções é que ele suporta a localização das mensagens de região ao vivo.
Para facilitar os anúncios, o elemento de item da lista no qual a ação ocorreu e o array de itens na lista são passados como argumentos, respectivamente.
{ announcement: { // grabbed is called when an item is picked up grabbed: (targetItem, items) => `${targetItem.innerText} grabbed`, // dropped is called when an item is dropped dropped: (targetItem, items) => `${targetItem.innerText} grabbed`, // reorder is called each time the order of the list is altered reorder: (targetItem, items) => { return `${targetItem.innerText} is now ${items.indexOf(targetItem) + 1} of ${items.length}` }, // cancel is called when a reordering is cancelled (via escape key) cancel: () => 'The initial order has been restored, reordering cancelled' } }
Texto de ajuda
É absolutamente vital que você forneça um texto de ajuda que descreva como usar a lista reordenável. Isso é algo que o Dragon Drop não faz por você para permanecer menos opinativo sobre como este texto é disponibilizado para tecnologia assistiva. A implementação recomendada é usar aria-describedby
para associar o texto de ajuda aos itens interativos da seguinte forma:
<p>Activate the reorder button and use the arrow keys to reorder the list or use your mouse to drag/reorder. Press escape to cancel the reordering.</p> <ul> <li> <button>Reorder Item 1</button> <span>Item 1</span> </li> <li> <button>Reorder Item 2</button> <span>Item 2</span> </li> <li> <button>Reorder Item 3</button> <span>Item 3</span> </li> </ul>
Dragon Drop no GitHub
A terceira versão do Dragon Drop foi lançada recentemente. Se você estiver interessado em usá-lo, consulte a documentação do Dragon Drop no GitHub. Um agradecimento especial aos criadores de Dragula, o módulo que Dragon Drop usa para interação com o mouse, bem como Aaron Pearlman, que projetou o incrível logotipo!
O Futuro do Dragão
Se a interação de arrastar e soltar for adicionada à especificação técnica WAI-ARIA no futuro, o fato de Dragon Drop depender de interação não padrão e regiões ao vivo pode mudar. Continuarei realizando testes garantindo que ele permaneça bem suportado pelo maior número possível de leitores de tela e me mantenha atualizado com as especificações ARIA mais recentes. Além disso, existem alguns recursos no pipeline, incluindo suporte para tela sensível ao toque/dispositivos móveis, bem como listas de várias colunas (como sprint boards). Outro recurso que pode ser adicionado no futuro é um componente Dragon Drop React.
Veja o Pen React Dragon Drop de Harris Schneiderman (@schne324) no CodePen.
Atualmente, Dragon Drop pode ser usado com React, como mostrado na demonstração abaixo, mas não é o ideal porque as alterações do DOM causadas pela reordenação da lista não são captadas pelo React, o que pode causar um comportamento inesperado. Peço a qualquer um que encontre bugs no Dragon Drop, ou mesmo tenha ideias de recursos para criar um problema no GitHub. Todos os comentários e contribuições são bem-vindos e muito apreciados!