- As listas em HTML devem ser escolhidas pelo significado e forma de interação, e não pela aparência visual, dividindo-se em listas de controle, ordenadas, de descrição, de menu e não ordenadas
- Para opções fixas, o correto é usar
<select>/<option>; para entradas com sugestão, <datalist>, sendo importante distinguir o comportamento de multiple, optgroup, size e value
<ol> é usado para procedimentos, eventos e contínuos em que mudar a ordem altera o significado; reversed inverte apenas a numeração, sem mudar a ordem real dos itens
<dl> foi ampliado no HTML5 além da lista de definições e serve para listas de descrição, pares termo-valor, metadados e depuração de JSON
<menu> é usado para listas de comandos, como botões de ferramentas; ele difere de nav em significado e conteúdo permitido, enquanto as demais listas gerais ficam com <ul>
Listas de controle: <select>/<option> e <datalist>
- Também é possível montar listas com as quais o usuário interage em formulários
-
Opções fixas com <select> e <option>
- Se o usuário deve poder escolher apenas entre os itens da lista, use
<select> e <option>
- No exemplo de lista de idiomas, opções como
Select a Language, English, French, Spanish e Portuguese são colocadas dentro de <select name="languages">
- O
<select> padrão permite escolher exatamente uma opção
- Para permitir a escolha de vários itens, adicione o atributo
multiple
- Ao usar
multiple, a exibição da lista muda e todas as opções ficam visíveis; o usuário pode escolher vários itens com Shift ou Cmd + clique
- Ao usar
select e option reais, a semântica padrão do navegador já cuida disso sem precisar adicionar manualmente aria-multiselectable a um elemento de lista com role="listbox"
-
Agrupe opções relacionadas com <optgroup>
- Se quiser agrupar idiomas por famílias linguísticas, use
<optgroup> para agrupar a lista de opções
- O exemplo cria
<optgroup> com label Germanic, Romance e Celtic, e coloca English, French, Spanish, Portuguese, Irish e Welsh em seus respectivos grupos
- Para impedir a seleção de um subgrupo específico, adicione o atributo
disabled ao <optgroup> correspondente
- No exemplo, o grupo
Celtic recebe disabled, desativando o conjunto que contém Irish e Welsh
-
Melhorando com recursos nativos do HTML
- Se for preciso uma separação visual entre grupos, é possível usar
<hr> dentro de <select>, onde ele é permitido
- O atributo
size controla quantos itens aparecem de uma vez, sendo útil em listas longas
- Ao usar
size junto com optgroup, os rótulos dos grupos também ocupam espaço de exibição
- O exemplo usa
<select name="languages" size="4" multiple> com grupos Germanic, Romance, Celtic e Afroasiatic, além de <hr /> entre eles e itens como Hebrew e Arabic
Lista de sugestões: <datalist>
- Se o usuário não precisa escolher obrigatoriamente só da lista, mas sim receber sugestões, use
<datalist>
- O
<datalist> é conectado em duas etapas
- Crie o
<datalist> e atribua um id a ele
- Coloque esse valor de
id no atributo list do <input> correspondente
- No exemplo de sugestão de idiomas,
<datalist id="languages"> contém opções English, French, Spanish, Portuguese, Irish, Welsh, Hebrew e Arabic, e é ligado ao campo de entrada com <input name="language" list="languages">
-
Comportamento de <option value>
- O valor padrão de
<option> é o texto que ele envolve; quando existe um atributo value, esse valor substitui o padrão e o texto passa a funcionar como rótulo
- Em
<select>, isso normalmente não causa problema porque o usuário vê apenas o texto, mas em <datalist> pode gerar confusão, já que o usuário vê o rótulo, seleciona, e o campo recebe o value
- No exemplo, ao selecionar
<option value="cy">Welsh</option>, o usuário vê Welsh, mas o campo recebe cy
- Ao usar
<datalist>, é preciso partir do princípio de que o valor inserido não é o rótulo, e sim o value
-
Combinação com vários tipos de input
<datalist> não serve apenas para opções de texto; ele também pode ser usado com outros tipos de input
- No exemplo de seleção por semana,
<input type="week" name="week" id="camp-week" min="2026-W2" max="2026-W51" list="preferred-weeks" /> é conectado a <datalist id="preferred-weeks">
- As semanas sugeridas são
2026-W22, 2026-W23, 2026-W24 e 2026-W25
-
Combinação com <input type="range">
<datalist> não se limita a valores de string e também funciona com números, então pode ser combinado com input do tipo range para criar pontos rotulados acima da faixa
- No exemplo de porcentagem de gorjeta,
<input type="range" name="tips" id="tips" min="0" max="50" step="1" list="recommended-tips" /> é conectado a <datalist id="recommended-tips"> com rótulos 10%, 18%, 30% e 45%
- Em navegadores da família Chrome, usa-se
@supports (x: attr(x type(percentage))) para ler o valor de label via attr(), declarar o valor como porcentagem com type() e posicionar as opções com position: absolute
- A abordagem para Firefox usa
@supports not (x: attr(x type(percentage))), e os valores são exibidos com ::before
- Essa técnica não garante que todos os navegadores se comportem da mesma forma nem que a exibição na tela seja idêntica
Lista ordenada: <ol>
- Use
<ol> para um conjunto de itens que precisa ser lido em uma ordem específica
- O critério não é se aparecem números ao lado dos itens, mas sim se o significado da lista muda quando a ordem dos itens é alterada
- Coleções adequadas para
<ol> incluem algoritmos, sequência de eventos, itens em um contínuo crescente ou decrescente, receitas e listas em ordem alfabética
- No exemplo da receita de pão de banana,
<ol> representa a sequência de pré-aquecer o forno e untar a forma, misturar os ingredientes, despejar a massa, assar por 60 minutos ou até que um palito saia limpo e deixar esfriar sobre uma grade
- Uma lista de ingredientes em ordem alfabética também se encaixa em
<ol>, pois segue o contínuo do alfabeto, com baking soda, bananas, brown sugar, butter, eggs, flour e salt
-
Aninhamento de listas ordenadas e não ordenadas
- Uma lista ordenada bem estruturada permite entender o que deve acontecer e em que ordem, mesmo sem ver a renderização do navegador
- No exemplo da receita, usa-se
<ol> nas etapas principais; dentro delas, itens cuja ordem não importa ficam em <ul>, e subetapas com ordem relevante voltam a usar <ol>
- A estrutura mantém a ordem principal de
Prepare, Mix, Pour, Bake e Cool, enquanto os itens paralelos dentro de Prepare e Bake ficam em <ul>, e os procedimentos dentro de Mix e Cool ficam em <ol>
-
reversed
- O atributo
reversed altera a numeração de crescente para decrescente
- Ele não muda a ordem real dos itens da lista
- Pode ser usado em uma lista de ingredientes e quantidades apresentada do maior para o menor, como
most to least
- O exemplo usa
<ol reversed> com eggs (2), flour (2 cups), bananas (2) (mashed), brown sugar (¾ cup), butter (½ cup), baking soda (1 teaspoon) e salt (¼ teaspoon)
-
Invertendo a ordem real dos itens com JavaScript
- Para inverter a lista de fato, é possível usar JavaScript para reordenar os filhos
li em ordem reversa e alternar o atributo reversed
- A função de exemplo transforma o resultado de
list.querySelectorAll('li') em array, aplica .reverse(), limpa com list.innerHTML = '' e insere novamente com list.append(...children)
- No fim, ela chama
list.toggleAttribute('reversed')
- O evento de exemplo usa
orderedList.addEventListener('dblclick', (evt) => { reverseList(orderedList) }) para inverter com um clique duplo
-
start
- O atributo
start serve para manter a continuidade da numeração ao dividir uma lista grande em várias listas ordenadas
- No exemplo da receita de pão de banana,
Prepare fica em ul, Mix usa <ol start=2>, Pour usa <ol start=5> e Cool usa <ol start=7>, preservando a sequência geral dos passos
- Mesmo que exista uma seção no meio representada como lista não ordenada, como
6: Bake, a lista ol seguinte pode começar com start=7 para manter o fluxo numérico de todo o procedimento
Lista de descrição: <dl>, <dt>, <dd>
- A lista de descrição (description list) é um tipo de lista que evita forçar todo conteúdo a caber em
ol ou ul
-
Lista de definições no HTML 4
- No HTML 4, ela não era chamada de
description list, mas sim de lista de definições (definition list), com um uso mais restrito voltado a fornecer definições
- A estrutura era composta pelo termo a ser definido em
<dt> e sua definição em <dd>; para um uso semanticamente preciso, o termo definido também era envolvido por <dfn>
- O exemplo liga
throw e yeet à mesma definição, e atribui definições separadas a no cap e bet
<dl>
<dt><dfn>throw</dfn></dt>
<dt><dfn>yeet</dfn></dt>
<dd>Verb. To discard at a high velocity</dd>
<dt><dfn>no cap</dfn></dt>
<dd>Interjection. Expresses authenticity and truthfulness, sometimes surprise.</dd>
<dt><dfn>bet</dfn></dt>
<dd>Interjection. Expresses agreement and affirmation.</dd>
</dl>
-
Significado ampliado no HTML5
- No HTML5, ela passou a ser uma lista de descrição que não se limita a definições, podendo ser usada quando há um “conjunto de termos e valores” relacionado
- O HTML5 permite um wrapper não semântico,
<div>, para agrupar <dt> e <dd> relacionados
- No exemplo de motores de navegador,
Chrome, Opera, Brave e Edge são agrupados em Blink-based browsers, enquanto Firefox, Tor e Librewolf ficam em Gecko-based browsers
<dl>
<div class="dl-item">
<dt>Chrome</dt>
<dt>Opera</dt>
<dt>Brave</dt>
<dt>Edge</dt>
<dd>Blink-based browsers</dd>
</div>
<div class="dl-item">
<dt>Firefox</dt>
<dt>Tor</dt>
<dt>Librewolf</dt>
<dd>Gecko-based browsers</dd>
</div>
</dl>
-
Metadados e depuração de JSON
- Quando há uma sequência de fatos e rótulos, uma lista de descrição é adequada para exibir metadados
- Um perfil de usuário também pode ser representado com
<dl>; no exemplo, First Frank, Last Taylor, Age 44, Job Writer e Handle Paceaux aparecem como pares <dt> e <dd>
- Em aplicações de página única, listas de descrição também podem ser usadas para depuração de JSON
- No exemplo
DebugJson, cada key, value do objeto é percorrido com Object.entries(obj); a chave é renderizada como <dt><var>...</var></dt> e o valor como <dd><code>...</code></dd>
- Se o valor for um objeto e não um array,
DebugJson.createDl(value) é chamado novamente para criar um <dl> aninhado; nos demais casos, value.toString() é colocado dentro de <code>
const debugJson = new DebugJson({foo: 'bar', arr: ['a', 'b'], car: 1}, '.container')
debugJson.render();
- Listas de descrição atendem amplamente à necessidade de pares chave-valor
Menu: <menu>
- O elemento
menu representa uma lista de comandos e está mais próximo da web interativa do que da simples renderização de conteúdo
menu é adequado para listas de botões que funcionam como “ferramentas”, como os controles de edição de texto em um editor rich text
- No exemplo de editor rich text, os botões
Strong, Emphasize e Strike são colocados em li dentro de menu
<menu>
<li><button onclick="strong()">Strong</button></li>
<li><button onclick="emphasize()">Emphasize</button></li>
<li><button onclick="strike()">Strike</button></li>
</menu>
- Pela especificação HTML, esse é um uso de toolbar, e em páginas interativas é comum que conjuntos de botões de ferramenta caibam em
menu
- O exemplo de controles de vídeo também entra em
menu, usando em button os atributos commandfor="vid-123" e command="--play", --mute, --fullscreen
<div class="player player--video">
<video source="whatever.mp4" id="vid-123"></video>
<menu>
<li><button commandfor="vid-123" command="--play">Play</button></li>
<li><button commandfor="vid-123" command="--mute">Mute</button></li>
<li><button commandfor="vid-123" command="--fullscreen">Fullscreen</button></li>
</menu>
</div>
Lista não ordenada: <ul>
ul é a lista coringa para as necessidades de listagem que não são resolvidas pelos outros tipos de lista nem por nav
- No HTML antigo, a diferença entre listas ordenadas e não ordenadas era mais visual, como números versus marcadores
- Hoje, considerando acessibilidade, leitores de tela e SEO, o foco deve estar menos na aparência e mais em se a ordem tem significado
- Uma lista de integrantes de banda se encaixa em
ul, já que a ordem não importa
<h3>Beatles</h3>
<ul>
<li>John Lennon</li>
<li>Paul McCartney</li>
<li>Ringo Star</li>
<li>George Harrison</li>
</ul>
- Uma lista de nomes de bandas também pode ser representada como lista não ordenada
<ul>
<li>Beatles</li>
<li>Rolling Stones</li>
<li>Van Halen</li>
<li>Foo Fighters</li>
</ul>
1 comentários
Comentários do Hacker News
Mesmo testando só os exemplos, parece que datalist não funciona bem no Mobile Safari
Se há problemas de compatibilidade em um mercado tão grande, talvez quase não existam cenários em que isso realmente valha a pena usar
É o tipo de informação de banho de água fria da realidade que eu não queria, mas precisava
Há mais de 10 anos trabalhei em um projeto que usava um widget de sugestão de entrada bem agressivo na UI, e na época usamos um plugin de jQuery
Era a parte mais complexa do frontend e, na prática, o principal motivo de usarmos jQuery naquele projeto
Lendo o texto, pensei que seria moleza reimplementar aquele frontend numa versão mínima e leve em JS, mas na prática não é assim, a menos que você entregue exatamente o seu ambiente para o dispositivo do usuário
Mesmo assim, os recursos incluídos hoje na especificação HTML são bem impressionantes
Desde que li XHTML no ensino médio, quase não acompanhei as mudanças da especificação, então talvez eu devesse dar uma olhada de vez em quando no que mudou
Mas a compatibilidade entre navegadores continua sendo uma dor de cabeça, como era naquela época
O exemplo de datalist definitivamente funciona no meu iPhone
Ele se integra à área de sugestões de autocomplete acima do teclado nativo do iOS
Só que não há como percorrer todas as sugestões, e provavelmente esse nem era o modo de uso pretendido do datalist
Mas o atributo
disableddegroupdefinitivamente não funcionaTambém não funciona no Firefox para Android
No meu primeiro emprego, há muito tempo, o datalist no Firefox não funcionava, e por causa disso o Firefox foi removido da lista de navegadores suportados
Já faz muito tempo que esse recurso é um problema para quem quer suportar navegadores além do Chrome
Não funciona bem com o GBoard no iOS
O exemplo que adiciona o atributo
disabledaoptgrouppara impedir a seleção de algumas opções parece quebrado no Mobile SafariNa prática, elas não ficam desativadas, e ainda dá para selecionar os itens desativados
Nas versões mais recentes do Safari isso deveria funcionar, então não parece exatamente quebrado, e sim em um estado estranho
https://caniuse.com/mdn-html_elements_optgroup_disabled
Parece possível que seja um bug do Safari
É por isso que é difícil usar HTML nativo para qualquer coisa além do básico
Mesmo que você leia bastante e entenda o suficiente para escrever um texto desses com confiança, nos comentários sempre aparecem comportamentos estranhos, limitações e falta de suporte dependendo da combinação de navegador e dispositivo
Um excesso de
divpode ser uma escolha que foi longe demais para o outro lado, mas pelo menos os comportamentos estranhos e as limitações costumam ser bem consistentes e visíveisPorque se encaixam de forma mais consistente com o que eu mesmo escrevi ou com o que o framework gerou
Texto interessante e abrangente
Infelizmente, hoje em dia há muitos desenvolvedores que entram direto em React sem aprender HTML, e agora com LLMs a chance de nunca aprender HTML é ainda maior
Por isso acabam procurando primeiro um componente React até para casos em que um HTML simples já bastaria
Ainda assim, acho isso ok
Quando precisei usar XML pela primeira vez, tive de aprender a especificação XML e gerar tudo manualmente
Era uma época em que praticamente não existiam bibliotecas de serialização
Depois vi gerações mais novas usando XML e, mais tarde, JSON como formato de troca sem aprender isso a fundo, e nada de ruim aconteceu
AJAX também passou de novidade empolgante para um estágio em que as pessoas nem sabiam o que a sigla significava, e hoje em dia a maioria mal reconhece o termo
O AJAX não morreu; só ficou tão comum que deixou de precisar de um nome separado
Meu problema é que eu aprendi HTML a fundo há 20 anos, e desde então só fui descobrindo por acaso, aos poucos, como ele mudou e melhorou
Com CSS isso é mais verdade ainda
Sinceramente, HTML é trabalhoso
Por exemplo, a abordagem à moda HTML para estilizar partes de um controle é usar pseudoclasses, mas às vezes os seletores mudam de navegador para navegador
Aí você precisa testar em cada navegador porque não dá para saber se realmente funciona direito
React não é só mais fácil, como também mais confiável
Se você fizer com React e
divs, pode esperar que funcione igual em todos os navegadoresO conteúdo é bom, mas não dá para esperar demais de
datalistNa prática faltam pontos de integração para que ele seja realmente útil, então não serve para muito além de protótipos pequenos
Fico curioso se um lint de HTML realmente ajuda a distinguir esse tipo de diferença
Também queria saber se existe algum linter que consiga impor esse tipo de escolha de tag semântica
A ideia de impor tags semânticas não me convence muito
HTML foi feito, antes de tudo, para que os autores o usem de forma criativa, e não acho que faça sentido forçar uma tag específica no lugar de outra
Acessibilidade é importante, mas já existem restrições suficientes
O mais próximo que conheço é https://github.com/kristoff-it/superhtml#diagnostics
SuperHTML valida não só a sintaxe, mas também o aninhamento dos elementos e os valores dos atributos
Não existe outro language server que implemente toda a especificação HTML no código de validação
Aprendi isso hoje
Fico me perguntando por que mais frameworks não aproveitam isso
Do ponto de vista da experiência do usuário, é o mesmo que uma lista comum
Se ajudar a entender o código, tudo bem usar, mas na árvore de acessibilidade do navegador e em todos os outros aspectos isso continua sendo só uma lista não ordenada
Para transmitir que se trata de uma lista de ações, é preciso adicionar atributos ARIA
O texto menciona
role=menu, mas isso por si só não basta; cada item também precisa do papelmenuitemO WAI Authoring Practices Guide explica os papéis e as expectativas de interação, mas não copie os exemplos de código literalmente, e em especial não use esse papel para menus de navegação
https://www.w3.org/WAI/ARIA/apg/patterns/menubar/
Gente esperta não aprende HTML difícil e resolve tudo com várias
divO HTML de hoje tem muitos recursos interessantes
Gosto de perguntar às pessoas o que elas acham que certos elementos fazem
Eu mesmo não acertei nada no começo
Mesmo tendo trabalhado por anos como líder de frontend, havia muita informação útil aqui que eu não conhecia
Acho que com certeza vamos começar a testar isso na empresa também
Seria ótimo se os designers gostassem da aparência padrão do datalist
O post do blog é muito bom, mas não consigo encontrar um jeito de ver a lista de todos os posts do blog de uma vez só
https://blog.frankmtaylor.com/archive não funciona
https://blog.frankmtaylor.com/archives também não
https://blog.frankmtaylor.com/posts também não funciona
https://blog.frankmtaylor.com/all também não existe
https://blog.frankmtaylor.com/blog também não é
Como há muita gente com mais de 10 mil favoritos, seria realmente útil ter uma página única de lista que mostrasse tudo o que já foi escrito até agora, sem descrição nem texto completo
Acho que você está falando de um sitemap
A maioria dos blogs tem um
sitemap.xmlcom a lista de todos os postsE também fico curioso para saber por que alguém iria querer passar por todos os 235 posts