Detalhes e resumo

Descubra como funcionam os elementos de detalhes e resumo muito úteis e onde usá-los.

Uma seta de expansão, às vezes conhecida como widget de divulgação, é um controle de interface do usuário que oculta e mostra conteúdo. Se você estiver lendo isso em web.dev e a janela de visualização tiver menos de 106 ems de largura, clicar em "Nesta página" vai revelar o sumário desta seção. Se ele não aparecer, diminua o navegador para ver a navegação do sumário nesta página como uma seta de expansão.

A interface gráfica do usuário acordeão é uma série de widgets de divulgação empilhados verticalmente. Um caso de uso comum para o acordeão é uma página de perguntas frequentes. Nesse caso, um FAQ em acordeão contém uma lista de perguntas visíveis. Quando clicada, a pergunta abre ou "revela" a resposta.

O jQuery inclui um padrão de interface do usuário de acordeão desde pelo menos 2009. A solução original de acordeão sem JavaScript incluía transformar cada pergunta das Perguntas frequentes em um <label> seguido da marca de seleção que ele rotulava e mostrar a resposta <div> quando a marca de seleção era marcada. O CSS era algo assim:

#FAQ [type="checkbox"] + div.answer {
  /* all the answer styles */
  display: none;
}
#FAQ [type="checkbox"]:checked + div.answer {
  display: block;
}

Por que o histórico? Widgets de divulgação, como acordeões, sem JavaScript ou hacks de controle de formulário, são uma adição relativamente recente. Os elementos <details> e <summary> só têm suporte total em navegadores modernos desde janeiro de 2020. Agora é possível criar widgets de divulgação funcionais, embora menos atraentes, com HTML semântico.

Os elementos <details> e <summary> são tudo o que você precisa: eles são uma maneira integrada de lidar com a expansão e o recolhimento de conteúdo. Quando um usuário clica ou toca em um <summary> ou solta a tecla Enter quando o <summary> está em foco, o conteúdo do <details> principal fica visível.

Como todo conteúdo semântico, você pode melhorar progressivamente os recursos e a aparência padrão. Nesse caso, apenas um pouco de CSS foi adicionado:

Isso significa que este CodePen (e todos os exemplos do CodePen) não tem JavaScript.

Alternar a visibilidade com o atributo open

O elemento <details> é o contêiner do widget de divulgação. O <summary> é o resumo ou a legenda do <details> pai. O resumo é sempre exibido, funcionando como um botão que alterna a exibição do restante do conteúdo do elemento pai. Ao interagir com o <summary>, a exibição dos elementos irmãos do resumo autônomo é alternada ao ativar o atributo open do elemento <details>.

O atributo open é booleano. Se estiver presente, não importa o valor ou a falta dele, isso indica que todo o conteúdo de <details> é mostrado ao usuário. Se o atributo open não estiver presente, apenas o conteúdo do <summary> será mostrado.

Como o atributo open é adicionado e removido automaticamente à medida que o usuário interage com o controle, ele pode ser usado em CSS para estilizar o elemento de maneira diferente com base no estado dele.

É possível criar um acordeão com uma lista de vários elementos <details>, cada um com um filho <summary>. Omitir o atributo open no HTML significa que todos os <details> serão recolhidos ou fechados, com apenas os cabeçalhos de resumo visíveis quando a página for carregada. Cada cabeçalho é o abridor do restante do conteúdo no <details> pai. Se você incluir o atributo open no HTML, o <details> será renderizado expandido, com o conteúdo visível, quando a página for carregada.

O conteúdo oculto no estado recolhido pode ser pesquisado em alguns navegadores, mas não em outros, mesmo que não faça parte do DOM. Se você pesquisar no Edge ou no Chrome, os detalhes que contêm um termo de pesquisa vão ser expandidos para mostrar a ocorrência. Esse comportamento não é replicado no Firefox ou Safari.

O <summary> precisa ser o primeiro filho de um elemento <details>, representando um resumo, uma legenda ou uma legenda para o restante do conteúdo do elemento <details> pai em que ele está aninhado. O conteúdo do elemento <summary> pode ser qualquer conteúdo de cabeçalho, texto simples ou HTML que possa ser usado em um parágrafo.

Ativar/desativar o marcador de resumo

Nos dois Codepens anteriores, há uma seta no lado inline-start do resumo. Normalmente, uma seta de expansão é apresentada na tela, um pequeno triângulo que gira (ou torce) para indicar o status aberto ou fechado e um rótulo ao lado do triângulo. O conteúdo do elemento <summary> rotula o widget de divulgação.

A seta giratória na parte de cima de cada seção é um ::marker definido no elemento <summary>. Assim como os itens de lista, o elemento <summary> é compatível com a propriedade abreviada list-style e as propriedades por extenso, incluindo list-style-type. É possível estilizar o triângulo de abertura com CSS, incluindo a mudança do marcador usado de um triângulo para qualquer outro tipo de marcador, incluindo uma imagem com list-style-image.

Para aplicar outros estilos, use um seletor semelhante a details summary::marker. O pseudoelemento ::marker aceita apenas um número limitado de estilos. Remover o ::marker e substituí-lo pelo ::before mais fácil de estilizar é uma prática comum. Os estilos CSS mudam um pouco o estilo do conteúdo gerado com base na presença (ou ausência) do atributo aberto. Você pode remover o ícone do widget de divulgação definindo list-style: none ou definir o conteúdo do marcador como none, mas sempre inclua indicadores visuais para informar aos usuários com visão que o conteúdo do resumo alterna para mostrar e ocultar conteúdo.

details summary::before {
  /* all the styles */
}
details[open] summary::before {
  /* changes applied when open only */
}

Este exemplo remove o marcador padrão e adiciona conteúdo gerado para criar um + quando os detalhes são fechados e um - quando são abertos.

Se você quiser que o bloco de detalhes fique aberto por padrão, inclua o atributo open na tag de abertura <details>. Você também pode adicionar espaço entre cada caixa de diálogo e fazer a transição da rotação do marcador criado com conteúdo gerado para melhorar a aparência:

Como os erros são tratados

Se você não incluir um <summary>, o navegador vai criar um para você, com um marcador e a palavra "detalhes". Esse resumo faz parte de uma raiz shadow e, portanto, não tem estilos de resumo CSS do autor aplicados.

Se você incluir um <summary>, mas ele não for o primeiro elemento no <details>, o navegador ainda vai mostrar o resumo corretamente. Não vai falhar se você incluir um link, um rótulo ou outro elemento interativo no resumo, mas os navegadores processam o conteúdo interativo de maneira diferente.

Por exemplo, se você incluir um link em um resumo, alguns navegadores vão adicionar o resumo e o link à ordem de tabulação padrão, mas outros não vão focar no link por padrão. Se você clicar em um <label> aninhado em um <summary>, alguns navegadores vão dar foco ao controle de formulário associado. Outros navegadores dão foco ao controle de formulário e alternam o <details> aberto ou fechado.

A interface HTMLDetailsElement

Como todos os elementos HTML, o HTMLDetailsElement herda todas as propriedades, métodos e eventos de HTMLElement e adiciona a propriedade de instância open e um evento toggle. A propriedade HTMLDetailsElement.open é um valor booleano que reflete o atributo HTML open, indicando se o conteúdo do elemento (sem contar o <summary>) deve ser mostrado ao usuário. O evento de alternância é acionado quando o elemento <details> é aberto ou fechado. É possível detectar esse evento usando addEventListener().

Se você quiser escrever um script para fechar os detalhes abertos quando o usuário abrir outros detalhes, remova o atributo "open" usando removeAttribute("open"):

Este é o único exemplo que usa JavaScript. Você provavelmente não precisa de JavaScript, exceto para fechar outros widgets abertos.

Lembre-se de que <details> e <summary> podem ser estilizados e até mesmo usados para criar dicas. No entanto, se você for usar esses elementos semânticos em casos de uso em que a semântica nativa não corresponde, mantenha sempre a acessibilidade. O HTML, na maior parte, é acessível por padrão. Nosso trabalho como desenvolvedores é garantir que nosso conteúdo permaneça acessível.

Teste seu conhecimento

Teste seus conhecimentos sobre detalhes e resumo.

O <summary> precisa ser o primeiro filho de qual elemento?

<p>
Tente novamente.
<details>
Correto.
<fieldset>
Tente novamente.