Ir para o conteúdo
OneKitly

As listas de tarefas em Markdown e o que se apresenta realmente em cada sítio

Publicado a 02/07/2025 · 12 min de leitura · Ferramentas de texto e idioma

Daniel Okonkwo

Daniel OkonkwoProgramador front-end e redator de Tecnologia na OneKitly

Desempenho web · Formatos de ficheiro

Verificado a partir de 4 fontes

Ver perfil
Em resumo

Uma lista de tarefas em Markdown — um item de lista que começa por [ ] ou [x] — não faz parte do CommonMark. Procurámos na especificação CommonMark 0.31.2 de 28 de janeiro de 2024: as expressões «task list» e «checkbox» aparecem zero vezes. As listas de tarefas estão definidas na especificação GitHub Flavored Markdown 0.29-gfm de 6 de abril de 2019, secção 5.3, como extensão. É essa toda a explicação para o mesmo ficheiro mostrar caixas no GitHub e parênteses retos literais noutros sítios. Passámos uma linha, «- [ ] comprar leite», por quatro motores: só o de sabor GitHub produziu um elemento input do tipo checkbox; a implementação de referência do CommonMark e outras duas configurações produziram um item de lista com o texto literal [ ] comprar leite. A regra do marcador é exata e pouco tolerante: uma série facultativa de espaços, um parêntesis reto de abertura, ou um espaço ou a letra x em qualquer caixa, um parêntesis reto de fecho, e depois pelo menos um espaço antes do conteúdo. «- [x]comprar» sem espaço sai como texto em todo o lado, «- []» sai como texto e «- [ ]» com dois espaços também. A mesma prudência vale para as tabelas, o rasurado e as ligações automáticas, também extensões, e para as notas de rodapé, que não estão em nenhuma das especificações.

As listas de tarefas não estão no CommonMark. São uma extensão do GitHub Flavored Markdown, e por isso o mesmo ficheiro mostra caixas num sítio e parênteses retos literais noutro. A regra exata do marcador, o que faz o aninhamento e uma tabela do que é CommonMark, do que é GFM e do que não é nenhum — verificado contra ambas as especificações e quatro motores de apresentação.

Uma linha, quatro motores, dois documentos diferentes

Pegámos numa única linha — um hífen, um espaço, um par de parênteses retos vazio, um espaço e algum texto — e apresentámo-la de quatro maneiras. Com a análise de sabor GitHub ativa, torna-se um item de lista com um elemento input do tipo checkbox, desativado. Com a mesma biblioteca e o sabor desligado, com a implementação de referência do CommonMark e com uma terceira biblioteca na sua configuração por omissão, torna-se um item de lista com os carateres [ ] seguidos do texto. Nada falhou. Quatro motores corretos produziram dois documentos diferentes a partir do mesmo ficheiro.

A razão está documentada, não é misteriosa. Procurámos «task list» e «checkbox» na especificação CommonMark 0.31.2 de 28 de janeiro de 2024: ambas aparecem zero vezes. A especificação GitHub Flavored Markdown 0.29-gfm de 6 de abril de 2019 tem uma secção 5.3 intitulada «Task list items (extension)». A palavra extensão faz todo o trabalho nesse título: o GFM é CommonMark mais cinco acrescentos com nome, e um motor que só implementa CommonMark não está avariado quando imprime as suas caixas como parênteses retos. Está correto.

A regra do marcador, caráter a caráter

A secção 5.3 do GFM define um item de lista de tarefas como um item cujo primeiro bloco é um parágrafo que começa por um marcador de lista de tarefas seguido de pelo menos um espaço antes de qualquer outro conteúdo. O marcador é um número facultativo de espaços, um parêntesis reto de abertura, ou um espaço ou a letra x em minúscula ou maiúscula, e um parêntesis reto de fecho. Cada palavra dessa frase suporta peso, e as falhas são silenciosas: executámos cada violação e todas saíram como texto vulgar nos quatro motores.

Omita o espaço depois do parêntesis de fecho e nada acontece: «- [x]comprar leite» é texto. Ponha dois espaços entre os parênteses e nada acontece: o marcador leva exatamente um caráter. Deixe os parênteses vazios e nada acontece. Use qualquer letra que não seja x e nada acontece. Afaste o marcador do início do parágrafo — «- comprar [ ] leite» — e nada acontece. Tire a lista e «[ ] comprar leite» é um parágrafo. O que funciona é mais generoso do que se pensa: a letra pode ser um X maiúsculo, o marcador pode ser um hífen, um asterisco ou um mais, a lista pode ser numerada, e uma tabulação conta como o espaço depois do parêntesis.

O aninhamento e a regra do primeiro bloco

As listas de tarefas aninham-se livremente, e a especificação mostra-o com um exemplo resolvido. Executámos um item pai com dois filhos indentados: caixa no pai, lista aninhada dentro do mesmo item e caixa em cada filho. Misturar itens marcados, não marcados e marcadores simples na mesma lista também resulta: o item simples continua simples e os marcados tornam-se caixas, o que torna uma lista de verificação legível como uma agenda mista.

O requisito de o primeiro bloco ser um parágrafo falha-se com facilidade. Ponha uma citação à cabeça — «- > [ ] citado» — e nenhum motor produz caixa, incluindo o de sabor GitHub, porque o primeiro bloco é uma citação e o marcador nunca tem a sua oportunidade. Acrescente um segundo parágrafo depois do marcado e a caixa sobrevive, colocada antes do primeiro parágrafo, com o segundo a seguir dentro do mesmo item. Não são esquisitices do motor: decorrem diretamente da frase da secção 5.3.

As extensões vizinhas e uma que não está em nenhuma especificação

As tabelas são a secção 4.10 da especificação GFM, também uma extensão. A nossa tabela de barras de três linhas saiu como um elemento table a sério sob a análise de sabor GitHub e sob as definições por omissão de outra biblioteca, e como um único parágrafo de barras literais sob a implementação de referência do CommonMark. O rasurado é a secção 6.5, e é mais estranho do que parece: a especificação permite um ou dois tis, portanto ~aqui~ fica rasurado, mas três ou mais não, portanto ~~~não~~~ fica literal. Uma biblioteca testada rasurava com dois tis mas não com um, e emitia um elemento de texto rasurado em vez do elemento de texto suprimido que a espec. GFM mostra. Dois motores podem ambos suportar o rasurado e ainda assim divergir na entrada e na saída.

As ligações automáticas vêm em duas formas e só uma é nativa. Um endereço entre ângulos é CommonMark e tornou-se ligação em todos os motores testados. Um endereço nu é a secção 6.9 do GFM, uma extensão com regras próprias: o esquema http é inserido antes de um endereço www e a pontuação final fica fora da ligação, pelo que «Visite www.commonmark.org.» liga o endereço e deixa o ponto de fora. Só a configuração de sabor GitHub produziu essas ligações; as outras deixaram o texto tal e qual.

As notas de rodapé são o caso instrutivo, porque não estão em nenhuma das especificações. A palavra footnote aparece exatamente uma vez na espec. do CommonMark e exatamente uma vez na do GFM, na mesma frase histórica da introdução sobre implementações que acrescentaram convenções para notas e tabelas. Os nossos quatro motores deixaram [^1] como texto literal e transformaram a linha de definição num parágrafo órfão. O próprio GitHub apresenta notas de rodapé, e é exatamente essa a armadilha: uma funcionalidade que já viu funcionar não está por isso no formato.

«Markdown» não é um formato

Duas especificações com números de versão diferentes e cinco anos entre elas, mais um conjunto de opções por biblioteca, não são um formato único. Os desacordos descem muito abaixo do nível das funcionalidades. Perante uma quebra de linha dura, dois dos nossos motores emitiram uma etiqueta de quebra autofechada e dois a forma HTML5. Perante um elemento script na fonte, dois passaram-no tal e qual para a saída e um escapou-o como texto; a espec. GFM dedica uma extensão inteira, a secção 6.11, a filtrar nove etiquetas concretas substituindo o seu ângulo de abertura por uma entidade. Nada disto é um erro.

A regra prática que daí resulta é curta: escreva para o motor que realmente visa, e saiba qual é. Um README numa forja, um gerador de sites de documentação, um cliente de conversa e um construtor de sites estáticos são quatro destinos com quatro conjuntos de funcionalidades, e um documento que aparece bem num deles não dá garantia nenhuma sobre os outros. Se o destino for desconhecido, fique dentro do CommonMark: títulos, ênfase, listas, código, ligações, ligações automáticas entre ângulos e citações são iguais em todo o lado.

Teste a ida e volta, e conte a partir da fonte

O teste mais barato de uma lista de verificação é aritmético. Escrevemos uma lista de sprint aninhada de cinco itens, dois marcados como feitos, contámo-los a partir da fonte markdown com um padrão que reconhece o marcador no início de um item e deu 2 de 5. Apresentar o mesmo documento com análise de sabor GitHub e contar os elementos input marcados no HTML também deu 2 de 5. Apresentá-lo com a implementação de referência do CommonMark deu zero elementos input — o documento está intacto, as caixas simplesmente nunca fizeram parte desse dialeto.

É esse o hábito que vale a pena manter: conte a partir da fonte, não da apresentação. O ficheiro markdown é o registo; o HTML é uma interpretação dele, e qual delas recebe depende de uma versão de biblioteca e de uma bandeira. O nosso gerador de listas escreve o marcador GFM exatamente como a secção 5.3 o especifica — marcador, espaço, parêntesis, um caráter, parêntesis, espaço — de modo que o ficheiro funciona onde a extensão é suportada e degrada para uma lista com parênteses legível onde não é. Se precisar que a caixa sobreviva em qualquer lado, a alternativa honesta é uma lista simples com a palavra «feito».

O que cada especificação define e o que quatro motores produziram de facto, executados no Node 26.3.0 com marked 18.0.7, a implementação de referência commonmark 0.31.2 e markdown-it 15.0.0 em duas predefinições. «GFM» significa aqui marked com gfm ativado; «markdown-it por omissão» é a sua configuração de origem.
FuncionalidadeNo CommonMark 0.31.2?Na espec. GFM 0.29?Saída da implementação de referênciaSaída do markdown-it por omissão
Lista de tarefas - [ ] / - [x]Não — 0 mençõesSim — secção 5.3, extensão[ ] literal no item de lista[ ] literal no item de lista
Tabela com barrasNãoSim — secção 4.10, extensãoUm parágrafo de barras literaisUm elemento table a sério
Rasurado com dois tisNãoSim — secção 6.5, extensãoTis literaisUm elemento rasurado, mas s em vez de del
Rasurado com um tiNãoSim — um ou dois tisTis literaisTis literais — exige dois
URL nu transformado em ligaçãoNãoSim — secção 6.9, extensãoTexto simplesTexto simples nas configurações testadas
Ligação automática entre ângulosSim — parte da especificação baseSim, herdadoUma ligação a sérioUma ligação a sério
Nota de rodapé [^1]NãoNão — também não na especificação[^1] literal e uma linha de definição órfã[^1] literal e uma linha de definição órfã
HTML em bruto deixado passarSim, por omissãoSim, menos nove etiquetas filtradasPassado tal e qualEscapado como texto
Gerador de checklist MarkdownTransforme uma lista de linhas numa lista de tarefas Markdown (- [ ] item).Experimentar a ferramenta

Perguntas frequentes

Porque é que as minhas caixas aparecem como [ ] em vez de caixas?
Porque o motor implementa CommonMark sem as extensões do GitHub. As listas de tarefas são a secção 5.3 da espec. GFM e não aparecem em lado nenhum do CommonMark 0.31.2. A segunda possibilidade é um marcador malformado: o espaço depois do parêntesis de fecho é obrigatório, entre os parênteses vai exatamente um caráter, e o marcador tem de abrir o primeiro parágrafo do item. Todas essas falhas saem como texto literal sem aviso nenhum.
O x tem de ser minúsculo?
Não. A espec. GFM diz a letra x em minúscula ou maiúscula, e confirmámos que ambas produzem uma caixa marcada. Nenhuma outra letra serve: um o entre os parênteses saiu como texto literal em todos os motores experimentados. Também não pode haver dois carateres — um marcador com dois espaços entre os parênteses não é um marcador.
As listas de tarefas podem ser aninhadas ou usadas numa lista numerada?
As duas coisas. A espec. GFM mostra listas de tarefas aninhadas livremente num exemplo resolvido, e a nossa execução produziu caixa no pai e em cada filho indentado. Um item de lista numerada funciona igual — o marcador vai depois do número e do ponto. O que não funciona é um item cujo primeiro bloco não seja um parágrafo: uma citação antes do marcador suprimiu a caixa em todos os motores.
As tabelas e o rasurado podem usar-se em qualquer lado?
Não. Ambas são extensões GFM, secções 4.10 e 6.5, e nenhuma está no CommonMark. A nossa tabela saiu como tabela a sério em duas configurações e como parágrafo de barras literais noutra. O rasurado é pior: a espec. GFM rasura o texto entre um ou dois tis mas não três, ao passo que outra biblioteca muito usada exigia dois e produzia um elemento HTML diferente para o resultado.
As notas de rodapé fazem parte do GitHub Flavored Markdown?
Segundo a especificação GFM publicada, não. A palavra footnote aparece nela exatamente uma vez, numa frase histórica da introdução, e não há secção alguma sobre notas. O próprio site do GitHub apresenta-as na mesma, o que ilustra bem a diferença entre uma especificação e um produto. Os quatro motores testados deixaram a chamada como texto literal e a definição como parágrafo órfão.

Artigos que podem interessar-lhe

Todos os guias
GuiaConverter entre formatos de lista sem perder dados: as regras de aspas que ninguém lêPassar de uma lista com quebras de linha para uma lista com vírgulas é trivial até um item conter uma vírgula. As regras de aspas da RFC 4180, porque um campo CSV pode conter uma quebra de linha, porque as folhas de cálculo europeias usam o ponto e vírgula, e o que um item vazio faz à ida e volta — cada caso executado e impresso.GuiaRetirar o Markdown: o que o texto simples perde, e em que se engana uma regexUma ligação torna-se texto com o destino apagado, uma lista aninhada perde a hierarquia, uma tabela torna-se uma fila de palavras. Depois a metade técnica: o markdown não tem uma especificação única, e um limpador à base de regex estraga um nome de ficheiro, um sinal de multiplicação e o interior de um bloco de código — tudo confrontado com um analisador a sério.ExplicaçãoOnde uma linha pode quebrar: o algoritmo Unicode por trás de cada parágrafo ajustado«Quebrar nos espaços» falha na maioria dos sistemas de escrita. O UAX #14 dá a cada caráter uma classe de quebra de linha; procurámos as nossas no Unicode 17.0.0 e executámos uma implementação conforme sobre espaços inquebráveis, hifenes condicionais, espaços de largura zero, URL, japonês e tailandês.TutorialFiltrar linhas por um padrão sem linha de comandosIsto é o grep para quem não usa grep, com uma diferença importante: a procura é uma subcadeia literal, pelo que uma expressão regular a sério devolve uma caixa vazia e nenhum erro. Cada afirmação foi verificada executando a ferramenta.ExplicaçãoContar palavras é ambíguo, e cada ferramenta responde de forma diferenteUma contagem de palavras é uma definição, não uma medição. Contámos o mesmo parágrafo de quatro maneiras e obtivemos 25, 28, 33 e 38; depois contámos 50 000 caracteres de prosa vulgar e obtivemos acordo dentro de 4,5 %. A diferença deve-se inteiramente a compostos, algarismos e URL.GuiaFormatar números para seis línguas: separadores, moeda e o regresso ao valor1 234,56 e 1,234.56 são o mesmo número, e confundi-los muda o valor que um leitor lê. Corremos Intl.NumberFormat para as seis localizações do site e imprimimos cada separador — incluindo o invisível que o francês usa — e depois medimos porque parseFloat não consegue desfazer nada disso.

Ferramentas relacionadas

Fontes

Detetaste um erro neste artigo?