Pular para o conteúdo

Skeleton

templates/components/Skeleton

O Skeleton é um marcador TEMPORÁRIO: existe só para ocupar o lugar do conteúdo enquanto ele carrega e depois sumir. Sua natureza não é interação nem conteúdo — é TEMPO (quando mostrar/esconder) e COMPOSIÇÃO (imitar o formato do que vem). Um único bloco quase nunca basta; ele vive em listas/parágrafos e precisa se comportar bem em cargas rápidas.

Base congelada

Conteúdo

Repetição (linhas/itens)

Renderiza o mesmo bloco N vezes…

Renderiza o mesmo bloco N vezes para formar um parágrafo ou lista de esqueleto, em vez de repetir a tag na mão.

Última linha curta

Num parágrafo repetido, encurta a largura…

Num parágrafo repetido, encurta a largura só da última linha para imitar a borda irregular de texto real.

Molde de conteúdo

Compõe vários blocos base num molde…

Compõe vários blocos base num molde que imita um tipo de conteúdo (arranjo aditivo, sem restilizar o bloco).

Atraso de exibição

Só mostra o esqueleto se o…

Só mostra o esqueleto se o carregamento passar de X ms, evitando a piscada em respostas rápidas.

Tempo mínimo em tela

Garante o esqueleto visível por pelo…

Garante o esqueleto visível por pelo menos X ms, evitando o flicker de quando o conteúdo chega quase instantâneo.

Trocar por conteúdo quando pronto

Vincula o esqueleto a um estado…

Vincula o esqueleto a um estado de carregamento e, ao ficar pronto, faz crossfade para os dados reais.

Comportamento

Pausar animação fora da tela

Pausa o pulse quando o bloco…

Pausa o pulse quando o bloco sai do viewport ou a aba fica inativa, poupando CPU/bateria em telas com muitos esqueletos.

Acessibilidade

Anúncio de carregamento (a11y)

Emite 'Carregando…' numa região viva enquanto…

Emite 'Carregando…' numa região viva enquanto o esqueleto está em tela e sinaliza 'pronto' ao concluir; rótulo definível.
Código gerado

Cole no Claude Code — ele acerta de primeira.

Skeleton (UI) — Design System (Symfony UX Toolkit / shadcn)

BASE CONGELADA (não mude por instância): Ficam imutáveis: a animação de pulse (animate-pulse), o preenchimento cinza (bg-muted), o canto padrão (rounded-md), a natureza puramente decorativa (um <div> sem texto, sem foco, sem ARIA de conteúdo) e o passthrough de classe via tailwind_merge. As dimensões (largura/altura) NÃO são identidade congelada — são inerentemente por-instância, pois o esqueleto precisa tomar o tamanho do conteúdo que substitui (o próprio demo oficial ajusta w/h e usa rounded-full no avatar). O que nenhum enricher pode tocar: a cor do fill, o tipo/velocidade visível do pulse e o raio padrão.

USO: <twig:Skeleton />

CAPACIDADES OPT-IN (ligue sem alterar o visual):
- Repetição (linhas/itens): Renderiza o mesmo bloco N vezes para formar um parágrafo ou lista de esqueleto, em vez de repetir a tag na mão. [number]- Última linha curta: Num parágrafo repetido, encurta a largura só da última linha para imitar a borda irregular de texto real. [select → Cheia (sem encurtar) / 3/4 da largura / 2/3 da largura / 1/2 da largura]- Molde de conteúdo: Compõe vários blocos base num molde que imita um tipo de conteúdo (arranjo aditivo, sem restilizar o bloco). [select → Parágrafo (linhas) / Mídia (avatar + linhas) / Cartão (bloco + texto) / Tabela (linhas × colunas) / Lista (item repetido)]- Atraso de exibição: Só mostra o esqueleto se o carregamento passar de X ms, evitando a piscada em respostas rápidas. [number]- Tempo mínimo em tela: Garante o esqueleto visível por pelo menos X ms, evitando o flicker de quando o conteúdo chega quase instantâneo. [number]- Trocar por conteúdo quando pronto: Vincula o esqueleto a um estado de carregamento e, ao ficar pronto, faz crossfade para os dados reais. [toggle]- Anúncio de carregamento (a11y): Emite 'Carregando…' numa região viva enquanto o esqueleto está em tela e sinaliza 'pronto' ao concluir; rótulo definível. [text]- Pausar animação fora da tela: Pausa o pulse quando o bloco sai do viewport ou a aba fica inativa, poupando CPU/bateria em telas com muitos esqueletos. [toggle]FAÇA:
- Use <twig:Nome> — a base é congelada, você é dono do template em templates/components/.
- Ligue apenas capacidades opt-in listadas (e_funcao=true); a aparência não muda ao ligá-las.
- Passe atributos extras (id, aria-*, name, data-*) via {{ attributes }}.
NÃO FAÇA:
- Não mude cor/fonte/cantos/espaçamento por instância — é decisão de BASE, na fonte única assets/styles/app.css.
- Não crie variante/fork para a mesma coisa — existe UMA base por componente.
- Não reimplemente o componente nem adicione toolchain Node.
TESTE ANTES DE MUDAR: "é função ou é base?" — função = capacidade opt-in; base = mude o token na fonte única (assets/styles/app.css), para todos.

A11Y (herdada da base): sem texto, sem foco, sem ARIA de conteúdo) e o passthrough de classe via tailwind_merge

Via MCP: tool get_component com {"id": "skeleton"} · list_capabilities("skeleton").

Spec crua: config/ds-specs/skeleton.json · Conectar o MCP.

Spec machine-readable (JSON)

{
    "$schema_version": "1.0",
    "id": "skeleton",
    "component": "Skeleton",
    "eixo": "ui",
    "particularidade": "O Skeleton é um marcador TEMPORÁRIO: existe só para ocupar o lugar do conteúdo enquanto ele carrega e depois sumir. Sua natureza não é interação nem conteúdo — é TEMPO (quando mostrar/esconder) e COMPOSIÇÃO (imitar o formato do que vem). Um único bloco quase nunca basta; ele vive em listas/parágrafos e precisa se comportar bem em cargas rápidas.",
    "base_congelada": "Ficam imutáveis: a animação de pulse (animate-pulse), o preenchimento cinza (bg-muted), o canto padrão (rounded-md), a natureza puramente decorativa (um &lt;div&gt; sem texto, sem foco, sem ARIA de conteúdo) e o passthrough de classe via tailwind_merge. As dimensões (largura/altura) NÃO são identidade congelada — são inerentemente por-instância, pois o esqueleto precisa tomar o tamanho do conteúdo que substitui (o próprio demo oficial ajusta w/h e usa rounded-full no avatar). O que nenhum enricher pode tocar: a cor do fill, o tipo/velocidade visível do pulse e o raio padrão.",
    "props": [],
    "capacidades": [
        {
            "id": "repeti-o-linhas-itens",
            "nome": "Repetição (linhas/itens)",
            "descricao": "Renderiza o mesmo bloco N vezes para formar um parágrafo ou lista de esqueleto, em vez de repetir a tag na mão.",
            "controle": "number",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (number). Ligue no configurador em /vitrine/ui/skeleton; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "ltima-linha-curta",
            "nome": "Última linha curta",
            "descricao": "Num parágrafo repetido, encurta a largura só da última linha para imitar a borda irregular de texto real.",
            "controle": "select",
            "opcoes": [
                "Cheia (sem encurtar)",
                "3/4 da largura",
                "2/3 da largura",
                "1/2 da largura"
            ],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/skeleton; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "molde-de-conte-do",
            "nome": "Molde de conteúdo",
            "descricao": "Compõe vários blocos base num molde que imita um tipo de conteúdo (arranjo aditivo, sem restilizar o bloco).",
            "controle": "select",
            "opcoes": [
                "Parágrafo (linhas)",
                "Mídia (avatar + linhas)",
                "Cartão (bloco + texto)",
                "Tabela (linhas × colunas)",
                "Lista (item repetido)"
            ],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ui/skeleton; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "atraso-de-exibi-o",
            "nome": "Atraso de exibição",
            "descricao": "Só mostra o esqueleto se o carregamento passar de X ms, evitando a piscada em respostas rápidas.",
            "controle": "number",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (number). Ligue no configurador em /vitrine/ui/skeleton; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "tempo-m-nimo-em-tela",
            "nome": "Tempo mínimo em tela",
            "descricao": "Garante o esqueleto visível por pelo menos X ms, evitando o flicker de quando o conteúdo chega quase instantâneo.",
            "controle": "number",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (number). Ligue no configurador em /vitrine/ui/skeleton; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "trocar-por-conte-do-quando-pronto",
            "nome": "Trocar por conteúdo quando pronto",
            "descricao": "Vincula o esqueleto a um estado de carregamento e, ao ficar pronto, faz crossfade para os dados reais.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/skeleton; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "an-ncio-de-carregamento-a11y",
            "nome": "Anúncio de carregamento (a11y)",
            "descricao": "Emite 'Carregando…' numa região viva enquanto o esqueleto está em tela e sinaliza 'pronto' ao concluir; rótulo definível.",
            "controle": "text",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (text). Ligue no configurador em /vitrine/ui/skeleton; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "pausar-anima-o-fora-da-tela",
            "nome": "Pausar animação fora da tela",
            "descricao": "Pausa o pulse quando o bloco sai do viewport ou a aba fica inativa, poupando CPU/bateria em telas com muitos esqueletos.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ui/skeleton; comportamento via controller Stimulus. Não altera a base."
        }
    ],
    "snippet_uso": "<twig:Skeleton />",
    "exemplo_demo": "<div class=\"flex items-center gap-4\">\n    <twig:Skeleton class=\"h-12 w-12 rounded-full\" />\n    <div class=\"space-y-2\">\n        <twig:Skeleton class=\"h-4 w-[250px]\" />\n        <twig:Skeleton class=\"h-4 w-[200px]\" />\n    </div>\n</div>",
    "regras": {
        "faca": [
            "Use <twig:Nome> — a base é congelada, você é dono do template em templates/components/.",
            "Ligue apenas capacidades opt-in listadas (e_funcao=true); a aparência não muda ao ligá-las.",
            "Passe atributos extras (id, aria-*, name, data-*) via {{ attributes }}."
        ],
        "nao_faca": [
            "Não mude cor/fonte/cantos/espaçamento por instância — é decisão de BASE, na fonte única assets/styles/app.css.",
            "Não crie variante/fork para a mesma coisa — existe UMA base por componente.",
            "Não reimplemente o componente nem adicione toolchain Node."
        ]
    },
    "a11y": "sem texto, sem foco, sem ARIA de conteúdo) e o passthrough de classe via tailwind_merge",
    "mcp": {
        "tool": "get_component",
        "args": {
            "id": "skeleton"
        }
    },
    "props_nota": "Sem props próprias declaradas: a base repassa atributos nativos via {{ attributes }} (id, name, type, value, aria-*, data-*). Props específicas, quando existem, ficam nos subcomponentes."
}