As interfaces da Web geralmente ocultam conteúdo para melhorar a experiência do usuário, economizar espaço na tela ou aumentar a performance da página. Métodos tradicionais como display: none ou visibility: hidden ocultam o conteúdo visualmente, mas também o tornam completamente inacessível para leitores de tela e recursos do navegador, como "Localizar na página".
Para ocultar o conteúdo visualmente, mas ainda permitir que ele seja pesquisável pelos usuários e que seja vinculado por links diretos usando fragmentos do URL e links "Rolar para fragmento de texto", use o elemento HTML <details> ou o atributo hidden="until-found". O elemento <details> geralmente é recomendado porque é mais simples de implementar e manter, mas há alguns casos mais complexos em que o <details> não é suficiente e o hidden="until-found" é necessário.
Exemplo:
- Se você quiser controle total sobre o estilo do mecanismo de exibição/ocultação.
- Se os controles de interface para mostrar/ocultar o conteúdo estiverem em outra parte do DOM.
- Se você não quiser ocultar o conteúdo depois que ele for mostrado.
Como fazer a implementação
O elemento <details> tem texto pesquisável e acessível por padrão, e nenhuma implementação especial é necessária. Se possível, use <details> em vez de hidden="until-found".
Se você precisar usar hidden="until-found", siga estas instruções:
- Aplique o atributo: adicione o atributo HTML
hidden="until-found"diretamente aos elementos que contêm o conteúdo que deve ser ocultado. - Sincronize o estado da interface: se a interface tiver estados relacionados que dependem da visibilidade do conteúdo (por exemplo, atualizar atributos ARIA, alternar classes CSS abertas/fechadas ou girar ícones de acordeão):
- Você PRECISA adicionar um listener de eventos para o evento
beforematch. - Registre o listener de eventos
beforematchdiretamente no elemento que contém o atributohidden="until-found". Como o evento se propaga, você também pode usar a delegação de eventos registrando um único listener em um elemento pai (como um contêiner de guias) para gerenciar várias seções ocultas de uma só vez. - Dentro do listener de eventos, execute a lógica para sincronizar os elementos da interface relacionados (como fechar outras guias abertas ou mudar o estado de um botão ativar/desativar).
- Você PRECISA adicionar um listener de eventos para o evento
Exemplo de código
Meta: renderizar um contêiner oculto em que o conteúdo permanece invisível para o usuário até que ele pesquise uma palavra nessa seção.
Como usar o elemento <details>
<details>
<summary>Click to expand</summary>
<p>This content is visually hidden.</p>
</details>
Declarações mutuamente exclusivas
Ao lidar com regiões de conteúdo mutuamente exclusivas, como um acordeão exclusivo, use o elemento HTML nativo <details> com um atributo name compartilhado.
<div class="accordion-group">
<!-- The name attribute creates an exclusive disclosure group -->
<details class="disclosure" name="my-accordion">
<summary>Section 1</summary>
<p>Section 1 content</p>
</details>
<details class="disclosure" name="my-accordion" open>
<summary>Section 2</summary>
<p>Section 2 content</p>
</details>
<details class="disclosure" name="my-accordion">
<summary>Section 3</summary>
<p>Section 3 content</p>
</details>
</div>
Como usar o atributo hidden="until-found"
<!-- The browser automatically removes hidden="until-found" upon a search match -->
<div class="hidden-container" hidden="until-found">
<p>This content is visually hidden.</p>
</div>
Declarações personalizadas mutuamente exclusivas
Ao lidar com regiões personalizadas mutuamente exclusivas controladas por botões externos, garanta que apenas o painel correspondente permaneça visível. No manipulador de eventos beforematch, você PRECISA sincronizar os estados ARIA relacionados, como definir aria-expanded="true" no botão de controle.
<div class="custom-accordion">
<div class="controls">
<button aria-expanded="true" aria-controls="panel-1" id="btn-1">Section 1</button>
<button aria-expanded="false" aria-controls="panel-2" id="btn-2">Section 2</button>
</div>
<div id="panel-1" class="panel">
<p>Section 1 content (visible)</p>
</div>
<div id="panel-2" class="panel" hidden="until-found">
<p>Section 2 content (hidden)</p>
</div>
</div>
const accordion = document.querySelector('.custom-accordion');
accordion.addEventListener('beforematch', (e) => {
// Hide all panels and synchronize button states before the browser reveals the matched panel
accordion.querySelectorAll('.panel').forEach((panel) => {
if (panel !== e.target) {
panel.hidden = 'until-found';
}
});
accordion.querySelectorAll('button').forEach((btn) => {
const controls = btn.getAttribute('aria-controls');
btn.setAttribute('aria-expanded', controls === e.target.id ? 'true' : 'false');
});
});
Práticas recomendadas para hidden="until-found"
- É RECOMENDÁVEL aplicar bordas, padding e planos de fundo a wrappers filhos aninhados, em vez de diretamente ao elemento com o atributo
hidden="until-found". Isso evita mudanças de layout não intencionais ou resquícios visuais enquanto o elemento está oculto. - NÃO aplique
display: none,visibility: hiddenou qualquer propriedade CSSdisplayouvisibilityassociada diretamente a elementos com o atributohidden="until-found". Isso interrompe a funcionalidade nativa e oculta permanentemente o conteúdo do índice da Pesquisa. - NÃO use
hidden="until-found"para informações sensíveis, tokens de dados internos ou dados irrelevantes que não devem ser expostos pela pesquisa. - NÃO use
hidden="until-found"como substituto para o texto "somente leitor de tela" (.sr-only).
Suporte ao navegador e estratégias de substituição
NÃO evite o uso de hidden="until-found" devido à falta de suporte do navegador, já que os benefícios de acessibilidade superam o custo de implementar um substituto.
hidden="until-found" de substituição
Para elementos da interface padrão, como acordeões ou seções "Leia mais", use o JavaScript para detectar recursos e mostrar todo o conteúdo se o recurso não for compatível.
if (!('onbeforematch' in HTMLElement.prototype)) {
// Expand all hidden content for unsupported browsers
document.querySelectorAll('[hidden="until-found"]').forEach((el) => {
el.removeAttribute('hidden');
// MANDATORY: also update any aria references to this element.
});
}
Para paradigmas de interface mutuamente exclusivos (como painéis exclusivos personalizados em que o conteúdo compartilha a mesma região visual), o substituto precisa extrair e mostrar todo o conteúdo de forma linear abaixo da área interativa principal, usando fragmentos de âncora de URL para permitir que os usuários naveguem diretamente para as respectivas seções.