O que é o atributo aria-expanded e como ele funciona?

O atributo aria-expanded é usado para fins de acessibilidade para indicar se um controle está expandido ou recolhido. É usado em conjunto com widgets recolhíveis como menus, acordeões e outros widgets de divulgação que controlam a visibilidade do conteúdo. O atributo aria-expanded é definido como true se o controle estiver expandido ou false se estiver recolhido. As informações fornecidas por aria-expanded permitem que pessoas que usam leitores de tela entendam o estado atual do controle (se está expandido ou recolhido). O atributo aria-expanded é aplicado ao elemento interativo que alterna a visibilidade de um widget colapsável. Por exemplo, se um botão alterna um menu expansível, o atributo aria-expanded é colocado no botão. Quando o menu está expandido, o atributo aria-expanded deve ser definido como true como neste exemplo:
<button aria-expanded="true">Menu</button>
Quando o menu estiver recolhido, ele deve ser definido como false em vez disso.
<button aria-expanded="false">Menu</button>
Você deve sempre ter o atributo aria-expanded definido como true ou false no elemento controlador. Por exemplo, se um botão alterna a visibilidade de um menu, o valor padrão para aria-expanded deve ser baseado na visibilidade padrão do menu. Se o menu estiver expandido por padrão, aria-expanded deve ser inicialmente definido como true. Se o menu estiver recolhido por padrão, aria-expanded deve ser inicialmente definido como false. O valor de aria-expanded deve ser atualizado dinamicamente usando JavaScript conforme o usuário interage com o elemento. Além disso, as propriedades aria-controls e aria-owns podem ser usadas em combinação com aria-expanded para estabelecer uma conexão programática entre o elemento controlador e o elemento que ele controla. Vamos começar com aria-controls. Quando usado com aria-expanded, o atributo aria-controls é usado para especificar o elemento que está sendo controlado. Por exemplo, um botão pode expandir ou recolher uma lista atuando como um menu. O valor de aria-controls será o id do elemento controlado (a lista de menu neste exemplo).
<link rel="stylesheet" href="styles.css">

<button aria-expanded="false" aria-controls="menu1">Menu</button>
<ul id="menu1" hidden>
  <li>...</li>
  <li>...</li>
</ul>

<script src="index.js"></script>
button {
  background-color: #0078d4;
  color: white;
  padding: 8px 12px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

button:hover {
  background-color: #005ea2;
}

ul {
  list-style: none;
  padding: 0;
  margin: 8px 0 0;
  border: 1px solid #ccc;
  border-radius: 4px;
  width: 150px;
  background: #fff;
}

li {
  padding: 8px;
  cursor: pointer;
}

li:hover {
  background-color: #f2f2f2;
}
const button = document.querySelector('button');
const menu = document.getElementById(button.getAttribute('aria-controls'));

button.addEventListener('click', () => {
  const expanded = button.getAttribute('aria-expanded') === 'true';
  button.setAttribute('aria-expanded', String(!expanded));
  menu.hidden = expanded;
});
Observe que a lista segue imediatamente o botão controlador. Para controles expansíveis como este, é melhor que o conteúdo expandido siga imediatamente o elemento que o controla no DOM. Isso evita que usuários de leitores de tela tenham que procurar pelo conteúdo expandido e facilita para usuários de teclado navegarem por quaisquer controles interativos no conteúdo expandido. Se não for possível colocar o conteúdo expandido imediatamente após o elemento controlador, o atributo aria-owns permite movê-lo virtualmente após o controle na árvore de acessibilidade. Isso permite que tecnologias assistivas como leitores de tela finjam que o conteúdo expandido está colocado diretamente após o controle no DOM.
<link rel="stylesheet" href="styles.css">

<button aria-owns="menu1" aria-expanded="true">Menu</button>
<main>
  <!-- an entire page worth of content --->
</main>
<ul id="menu1">
  <li>...</li>
  <li>...</li>
</ul>

<script src="index.js"></script>
button {
  background-color: #0078d4;
  color: white;
  padding: 8px 12px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  margin-bottom: 10px;
}

button:hover {
  background-color: #005ea2;
}

ul {
  list-style: none;
  padding: 0;
  margin: 8px 0;
  border: 1px solid #ccc;
  border-radius: 4px;
  width: 150px;
  background: #fff;
  position: absolute;
  z-index: 10;
}

li {
  padding: 8px;
  cursor: pointer;
}

li:hover {
  background-color: #f2f2f2;
}
const button = document.querySelector('button');
const menu = document.getElementById(button.getAttribute('aria-owns'));

button.addEventListener('click', () => {
  const expanded = button.getAttribute('aria-expanded') === 'true';
  button.setAttribute('aria-expanded', String(!expanded));
  menu.hidden = expanded;
});

// Close the menu if user clicks outside
document.addEventListener('click', (e) => {
  if (!button.contains(e.target) && !menu.contains(e.target)) {
    button.setAttribute('aria-expanded', 'false');
    menu.hidden = true;
  }
});
Existem desvantagens em usar o atributo aria-owns. Isso cria uma verbosidade desnecessária para usuários de leitores de tela, já que a maioria dos leitores de tela lerá automaticamente todo o conteúdo do elemento expandido quando ele for expandido pela primeira vez. Também não altera a ordem de tabulação, potencialmente forçando usuários de teclado a navegar por todos os outros controles interativos na página antes de alcançar o conteúdo expandido, a menos que você gerencie a ordem de tabulação com JavaScript. Idealmente, o conteúdo expansível deve ser colocado após o elemento de controle e o atributo aria-owns deve ser usado apenas em um cenário de último caso quando isso não for possível. Se precisar ser usado, você precisará testar minuciosamente com uma ampla variedade de leitores de tela e navegadores para garantir que sua implementação seja acessível para todos. E só um lembrete, quando você usar aria-controls ou aria-owns, o valor de aria-expanded deve continuar sendo atualizado conforme o controle é expandido e recolhido. O atributo aria-expanded indica se um controle está expandido ou recolhido. Estas informações são essenciais para usuários de leitores de tela, ajudando-os a entender o estado atual de elementos recolhíveis como menus, acordeões e outros widgets de divulgação semelhantes. Ao usar aria-expanded corretamente, você pode criar uma experiência de usuário intuitiva para todos.
Este módulo não possui perguntas. Marque como concluído.