Quais São Alguns Estados ARIA Comuns Usados em Elementos de Controle Personalizados?
Elementos de controle de formulário semânticos como
input, select, textarea, button e fieldset possuem estados incorporados que são transmitidos para tecnologias assistivas.
Por exemplo, você pode usar o atributo disabled para desabilitar um botão ou o atributo checked para indicar que uma caixa de seleção está marcada.
Mas se você estiver criando um elemento de controle personalizado, precisa usar atributos ARIA para transmitir o estado do controle às tecnologias assistivas.
Nesta lição, discutiremos alguns estados ARIA comuns que você pode usar em elementos de controle personalizados.
O primeiro estado ARIA que discutiremos é aria-selected. Este estado é usado para indicar que um elemento está selecionado. Você pode usar esse estado em controles personalizados como uma interface com abas, uma listbox ou uma grid.
Aqui está um exemplo de como você pode usar aria-selected em um controle de abas personalizado:
<link rel="stylesheet" href="styles.css">
<div role="tablist">
<button role="tab" aria-selected="true">Tab 1</button>
<button role="tab" aria-selected="false">Tab 2</button>
<button role="tab" aria-selected="false">Tab 3</button>
</div>
<script src="index.js"></script>
[role="tablist"] {
display: flex;
border-bottom: 2px solid #ddd;
gap: 0.25rem;
font-family: system-ui, sans-serif;
}
[role="tab"] {
appearance: none;
border: none;
background: none;
padding: 0.5rem 1rem;
cursor: pointer;
font-size: 1rem;
color: #444;
border-radius: 4px 4px 0 0;
transition: background-color 0.2s, color 0.2s;
}
[role="tab"]:hover {
background-color: #f3f3f3;
}
[role="tab"][aria-selected="true"] {
background-color: #fff;
color: #0078d4;
border: 2px solid #0078d4;
border-bottom: 2px solid #fff;
font-weight: 600;
position: relative;
z-index: 1;
}
[role="tab"]:focus {
outline: 2px solid #0078d4;
outline-offset: 2px;
}
document.addEventListener("click", (event) => {
const clickedTab = event.target.closest('[role="tab"]');
if (!clickedTab) return;
const tablist = clickedTab.closest('[role="tablist"]');
const tabs = tablist.querySelectorAll('[role="tab"]');
tabs.forEach((tab) => {
const isSelected = tab === clickedTab;
tab.setAttribute("aria-selected", isSelected);
tab.tabIndex = isSelected ? 0 : -1;
});
});
document.addEventListener("keydown", (event) => {
const activeTab = document.activeElement;
if (activeTab.getAttribute("role") !== "tab") return;
const tablist = activeTab.closest('[role="tablist"]');
const tabs = Array.from(tablist.querySelectorAll('[role="tab"]'));
const index = tabs.indexOf(activeTab);
let newIndex = index;
if (event.key === "ArrowRight") newIndex = (index + 1) % tabs.length;
if (event.key === "ArrowLeft") newIndex = (index - 1 + tabs.length) % tabs.length;
if (newIndex !== index) {
tabs[newIndex].focus();
tabs[newIndex].click();
}
});
As abas são usadas para exibir múltiplos painéis de conteúdo em um espaço limitado. O estado aria-selected é usado para indicar qual aba está atualmente selecionada.
Quando o usuário seleciona uma aba, o estado aria-selected da aba selecionada é definido como true e o estado aria-selected das outras abas é definido como false.
Outro estado ARIA comum é aria-disabled. Este estado é usado para indicar que um elemento está desabilitado apenas para pessoas que utilizam tecnologias assistivas, como leitores de tela. É importante notar que aria-disabled na verdade não desabilita o elemento. Cabe a você, o desenvolvedor, fazer com que pareça e funcione como um elemento desabilitado. Este atributo também é comumente usado em elementos HTML nativos no lugar do atributo disabled. Qual você escolher dependerá do contexto em que o botão está sendo usado.
Aqui está um exemplo de como você pode usar aria-disabled em um botão de edição personalizado:
<link rel="stylesheet" href="styles.css">
<div role="button" tabindex="-1" aria-disabled="true">Edit</div>
[role="button"] {
display: inline-block;
background-color: #0078d4;
color: #fff;
padding: 0.5rem 1rem;
border-radius: 6px;
font-family: system-ui, sans-serif;
font-size: 1rem;
text-align: center;
cursor: pointer;
user-select: none;
transition: background-color 0.2s, transform 0.1s, opacity 0.2s;
}
[role="button"]:not([aria-disabled="true"]):hover {
background-color: #005fa3;
}
[role="button"]:not([aria-disabled="true"]):focus {
outline: 2px solid #005fa3;
outline-offset: 2px;
}
[role="button"]:not([aria-disabled="true"]):active {
transform: scale(0.97);
}
[role="button"][aria-disabled="true"] {
opacity: 0.5;
pointer-events: none;
cursor: not-allowed;
background-color: #b0b0b0;
color: #f2f2f2;
}
O atributo aria-disabled é usado para informar aos usuários de leitores de tela que o botão de edição está desativado e não pode ser interagido. Novamente, isso não desativa realmente o botão. Ao usar aria-disabled, você precisará aplicar estilos e JavaScript para fazer com que o controle pareça e se comporte como um botão desabilitado.
Na maioria dos casos, você provavelmente usará o elemento nativo button, mas há casos em que pode ser necessário usar um controle personalizado. Portanto, é essencial saber como transmitir o estado do controle para tecnologias assistivas.
O próximo estado ARIA que discutiremos é aria-haspopup. Este estado é usado para indicar que um elemento interativo acionará um elemento popup quando ativado. Você só pode usar o atributo aria-haspopup quando o popup tiver um dos seguintes papéis: menu, listbox, tree, grid e dialog. O valor de aria-haspopup deve ser um destes papéis ou true, que por padrão é o papel menu.
Aqui está um exemplo de um menu de editor de arquivos que usa aria-haspopup:
<link rel="stylesheet" href="styles.css">
<button id="menubutton" aria-haspopup="menu" aria-controls="filemenu" aria-expanded="false">File</button>
<ul id="filemenu" role="menu" aria-labelledby="menubutton" hidden>
<li role="menuitem" tabindex="-1">Open</li>
<li role="menuitem" tabindex="-1">New</li>
<li role="menuitem" tabindex="-1">Save</li>
<li role="menuitem" tabindex="-1">Delete</li>
</ul>
#menubutton {
background-color: #0078d4;
color: #fff;
border: none;
padding: 8px 14px;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
position: relative;
}
#menubutton:hover,
#menubutton:focus {
background-color: #005ea2;
outline: none;
}
#filemenu {
list-style: none;
padding: 4px 0;
margin: 4px 0 0;
border: 1px solid #ccc;
border-radius: 4px;
background-color: #fff;
width: 160px;
position: absolute;
z-index: 1000;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
#filemenu[hidden] {
display: none;
}
#filemenu [role="menuitem"] {
display: block;
padding: 8px 12px;
font-size: 14px;
color: #333;
cursor: pointer;
}
#filemenu [role="menuitem"]:hover,
#filemenu [role="menuitem"]:focus {
background-color: #e5f1fb;
outline: none;
}
#filemenu [role="menuitem"]:focus-visible {
box-shadow: inset 0 0 0 2px #0078d4;
}
O estado aria-haspopup é usado para indicar que o botão do menu File abrirá um menu popup quando ativado. Usuários de leitor de tela podem ouvir esta informação adicional quando navegarem até o botão.
Você precisará usar JavaScript para mostrar e esconder o menu popup e para implementar o suporte adequado ao teclado para interagir com o menu. Além disso, observe que o papel ARIA menu se refere a um tipo muito específico de menu. Geralmente se refere a uma lista de ações que o usuário pode invocar, semelhante a um menu em uma aplicação desktop. Não inclui usos mais comuns do que normalmente nos referimos como "menus", como menus de navegação. Na prática, a maioria dos "menus" que você cria na web não serão menus ARIA e você não usará aria-haspopup com eles.
O próximo estado ARIA que discutiremos é aria-required. O atributo aria-required é usado para indicar que um campo precisa ser preenchido antes que o formulário seja enviado.
Aqui está um exemplo de como trabalhar com o atributo aria-required para um controle de formulário personalizado.
<link rel="stylesheet" href="styles.css">
<div id="name-label">Full Name*</div>
<div role="textbox" contenteditable aria-labelledby="name-label" aria-required="true" id="name"></div>
#name-label {
font-family: system-ui, sans-serif;
font-size: 0.95rem;
font-weight: 600;
margin-bottom: 0.25rem;
color: #333;
}
[role="textbox"] {
display: block;
width: 100%;
min-height: 2rem;
padding: 0.5rem 0.75rem;
border: 1.5px solid #ccc;
border-radius: 4px;
font-family: system-ui, sans-serif;
font-size: 1rem;
color: #222;
background-color: #fff;
line-height: 1.4;
transition: border-color 0.2s, box-shadow 0.2s;
}
[role="textbox"]:hover {
border-color: #999;
}
[role="textbox"]:focus {
outline: none;
border-color: #0078d4;
box-shadow: 0 0 0 3px rgba(0, 120, 212, 0.25);
}
[role="textbox"]:empty::before {
content: attr(data-placeholder);
color: #aaa;
pointer-events: none;
}
[role="textbox"][aria-required="true"] {
border-left: 3px solid #e81123;
padding-left: calc(0.75rem - 3px);
}
Precisamos usar o atributo contenteditable para que os usuários possam digitar sua entrada. Também estamos usando o atributo aria-required definido como true para indicar que este controle de formulário personalizado é obrigatório.
Para fazer o controle do formulário parecer um controle de formulário normal, você precisaria adicionar CSS. Você também precisaria adicionar JavaScript para evitar que o formulário seja enviado sem conteúdo.
Se o rótulo já contém a palavra required, então você deve omitir o atributo aria-required. Isso garante que os leitores de tela anunciem a palavra necessária apenas uma vez.
Na maioria dos casos, você provavelmente usará os elementos nativos label e form com o atributo required. Mas se você precisar criar um controle de formulário personalizado, então é importante adicionar o atributo aria-required quando necessário.
Além disso, o atributo aria-required também pode ser usado em inputs nativos de formulário, como os elementos input, textarea e select. Isso é frequentemente preferido ao atributo nativo required, já que o atributo required pode ter potenciais problemas de usabilidade e acessibilidade, particularmente com o tratamento de erros padrão fornecido pelo navegador. No final, você precisará testar para determinar qual atributo é melhor para a sua situação.
O último estado ARIA que discutiremos é aria-checked. Este atributo é usado para indicar se um elemento está no estado checked. É mais comumente usado ao criar caixas de seleção personalizadas, botões de opção, interruptores e caixas de lista.
Aqui está um exemplo de como você pode usar aria-checked em um controle de caixa de seleção personalizado:
<link rel="stylesheet" href="styles.css">
<div role="checkbox" aria-checked="true" tabindex="0">Checkbox</div>
[role="checkbox"] {
display: inline-flex;
align-items: center;
gap: 0.5rem;
font-family: system-ui, sans-serif;
font-size: 1rem;
cursor: pointer;
user-select: none;
color: #222;
}
[role="checkbox"]::before {
content: "";
display: inline-block;
width: 1rem;
height: 1rem;
border: 2px solid #666;
border-radius: 4px;
background-color: #fff;
transition: all 0.2s ease;
box-sizing: border-box;
}
[role="checkbox"]:hover::before {
border-color: #0078d4;
}
[role="checkbox"]:focus::before {
outline: 2px solid #0078d4;
outline-offset: 2px;
}
[role="checkbox"][aria-checked="true"]::before {
background-color: #0078d4;
border-color: #0078d4;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14'><path fill='white' d='M5.2 10.4L2 7.2l1.1-1.1 2.1 2.1L10.9 2.5 12 3.6z'/></svg>");
background-repeat: no-repeat;
background-position: center;
}
[role="checkbox"][aria-disabled="true"] {
opacity: 0.5;
pointer-events: none;
cursor: not-allowed;
}
Elementos nativos de checkbox possuem um estado checked embutido que é transmitido para tecnologias assistivas. Mas se você estiver criando um controle de caixa de seleção personalizado, será necessário usar o atributo aria-checked para indicar seu estado.
Quando o usuário interage com o controle de caixa de seleção personalizada, você precisará usar o estado aria-checked para refletir o novo estado da caixa de seleção. Quando a caixa de seleção está marcada, o atributo aria-checked é definido como true. Quando não está marcado, é definido como false.
Elementos nativos normalmente têm melhor suporte e recursos de acessibilidade integrados.
No entanto, se você precisar criar controles personalizados, usar atributos ARIA é essencial para transmitir o estado desses controles para tecnologias assistivas de forma eficaz.
Como sempre, teste seu trabalho para garantir que os atributos ARIA sejam aplicados corretamente e que o controle personalizado funcione de uma maneira que seja acessível e fácil de usar.Este módulo não possui perguntas. Marque como concluído.