Pular para o conteúdo

Tabs

templates/components/Tabs

Tabs é um navegador de painéis mutuamente exclusivos: uma barra de gatilhos revela um de vários painéis por vez, com um único estado de "aba ativa" (Stimulus data-controller=tabs). Sua particularidade não é estilizar cada aba, mas gerir muitos gatilhos numa barra estreita e preservar/compartilhar qual painel está aberto.

Base congelada

Overview
View your key metrics and recent project activity. Track progress across all your active projects.
You have 12 active projects and 3 pending tasks.
Analytics
Track performance and user engagement metrics. Monitor trends and identify growth opportunities.
Page views are up 25% compared to last month.
Reports
Generate and download your detailed reports. Export data in multiple formats for analysis.
You have 5 reports ready and available to export.
Settings
Manage your account preferences and options. Customize your experience to fit your needs.
Configure notifications, security, and themes.

Conteúdo

Contador por aba

Badge numérico aditivo no gatilho (ex.:…

Badge numérico aditivo no gatilho (ex.: Inbox 12) para sinalizar volume ou pendências de cada painel. posicionável

Overflow de abas

Quando os gatilhos não cabem na…

Quando os gatilhos não cabem na largura, define como acomodá-los mantendo a barra em linha única.

Lembrar última aba

Persiste a última aba aberta em…

Persiste a última aba aberta em localStorage e a restaura automaticamente no próximo acesso.

Carregamento tardio do painel

Adia render/fetch do conteúdo até a…

Adia render/fetch do conteúdo até a aba ser ativada pela 1ª vez — ideal para painéis pesados ou via AJAX.

Proteção de edição não salva

Marca com ponto (•) as abas…

Marca com ponto (•) as abas com edições pendentes e pede confirmação antes de trocar de painel em edição.

Comportamento

Aba fechável

Adiciona botão × ao gatilho para…

Adiciona botão × ao gatilho para o usuário fechar/remover aquela aba, emitindo um evento de fechamento.

Botão "nova aba" (+)

Botão + na barra para criar…

Botão + na barra para criar abas dinamicamente, estilo navegador/editor, sem sair do componente. posicionável

Sincronizar aba com a URL

Reflete a aba ativa na URL…

Reflete a aba ativa na URL para deep-link, favoritar, compartilhar e usar voltar/avançar do navegador.
Código gerado

Cole no Claude Code — ele acerta de primeira.

Tabs (UX) — Design System (Symfony UX Toolkit / shadcn)

BASE CONGELADA (não mude por instância): Congelados e imutáveis: tipografia (text-sm, font-medium), cantos (rounded-lg na List, rounded-md no Trigger), espaçamento (p-[3px], gaps), cores (bg-muted, text-muted-foreground/foreground), altura h-8, as duas variantes visuais default/line e a orientação horizontal/vertical (props da base), os slots de ícone inline-start/inline-end já previstos no Trigger, e toda a a11y — role=tablist/tab/tabpanel, aria-selected/controls/labelledby, foco visível (ring), estado disabled e suporte RTL/LTR. O ato de trocar de aba é o comportamento-base. Nenhum enricher toca fonte/cor/cantos/espaçamento; por isso orientação, variantes e ícone NÃO entram como enrichers (são base).

USO: <twig:Tabs>…</twig:Tabs>

CAPACIDADES OPT-IN (ligue sem alterar o visual):
- Contador por aba: Badge numérico aditivo no gatilho (ex.: Inbox 12) para sinalizar volume ou pendências de cada painel. [toggle]- Aba fechável: Adiciona botão × ao gatilho para o usuário fechar/remover aquela aba, emitindo um evento de fechamento. [toggle]- Botão "nova aba" (+): Botão + na barra para criar abas dinamicamente, estilo navegador/editor, sem sair do componente. [toggle]- Overflow de abas: Quando os gatilhos não cabem na largura, define como acomodá-los mantendo a barra em linha única. [select → Rolagem horizontal com setas / Menu "mais" (…)]- Sincronizar aba com a URL: Reflete a aba ativa na URL para deep-link, favoritar, compartilhar e usar voltar/avançar do navegador. [select → Hash (#aba) / Query (?tab=)]- Lembrar última aba: Persiste a última aba aberta em localStorage e a restaura automaticamente no próximo acesso. [toggle]- Carregamento tardio do painel: Adia render/fetch do conteúdo até a aba ser ativada pela 1ª vez — ideal para painéis pesados ou via AJAX. [select → Renderizar ao ativar / Buscar via AJAX / Sempre recarregar]- Proteção de edição não salva: Marca com ponto (•) as abas com edições pendentes e pede confirmação antes de trocar de painel em edição. [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): Congelados e imutáveis: tipografia (text-sm, font-medium), cantos (rounded-lg na List, rounded-md no Trigger), espaçamento (p-[3px], gaps), cores (bg-muted, text-muted-foreground/foreground), altura h-8, as duas variantes visuais default/line e a orientação horizontal/vertical (props da base), os slots de ícone inline-start/inline-end já previstos no Trigger, e toda a a11y — role=tablist/tab/tabpanel, aria-selected/controls/labelledby, foco visível (ring), estado disabled e suporte RTL/LTR. por isso orientação, variantes e ícone NÃO entram como enrichers (são base)

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

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

Spec machine-readable (JSON)

{
    "$schema_version": "1.0",
    "id": "tabs",
    "component": "Tabs",
    "eixo": "ux",
    "particularidade": "Tabs é um navegador de painéis mutuamente exclusivos: uma barra de gatilhos revela um de vários painéis por vez, com um único estado de \"aba ativa\" (Stimulus data-controller=tabs). Sua particularidade não é estilizar cada aba, mas gerir muitos gatilhos numa barra estreita e preservar/compartilhar qual painel está aberto.",
    "base_congelada": "Congelados e imutáveis: tipografia (text-sm, font-medium), cantos (rounded-lg na List, rounded-md no Trigger), espaçamento (p-[3px], gaps), cores (bg-muted, text-muted-foreground/foreground), altura h-8, as duas variantes visuais default/line e a orientação horizontal/vertical (props da base), os slots de ícone inline-start/inline-end já previstos no Trigger, e toda a a11y — role=tablist/tab/tabpanel, aria-selected/controls/labelledby, foco visível (ring), estado disabled e suporte RTL/LTR. O ato de trocar de aba é o comportamento-base. Nenhum enricher toca fonte/cor/cantos/espaçamento; por isso orientação, variantes e ícone NÃO entram como enrichers (são base).",
    "props": [
        {
            "name": "defaultValue",
            "type": "string",
            "default": "",
            "description": "define the open Tabs at initial rendering. Defaults to `` #}"
        },
        {
            "name": "orientation",
            "type": "'horizontal'|'vertical'",
            "default": "horizontal",
            "description": "define the visual orientation. Defaults to `horizontal` #}"
        }
    ],
    "capacidades": [
        {
            "id": "contador-por-aba",
            "nome": "Contador por aba",
            "descricao": "Badge numérico aditivo no gatilho (ex.: Inbox 12) para sinalizar volume ou pendências de cada painel.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": true,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ux/tabs; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "aba-fech-vel",
            "nome": "Aba fechável",
            "descricao": "Adiciona botão × ao gatilho para o usuário fechar/remover aquela aba, emitindo um evento de fechamento.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ux/tabs; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "bot-o-nova-aba",
            "nome": "Botão \"nova aba\" (+)",
            "descricao": "Botão + na barra para criar abas dinamicamente, estilo navegador/editor, sem sair do componente.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": true,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ux/tabs; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "overflow-de-abas",
            "nome": "Overflow de abas",
            "descricao": "Quando os gatilhos não cabem na largura, define como acomodá-los mantendo a barra em linha única.",
            "controle": "select",
            "opcoes": [
                "Rolagem horizontal com setas",
                "Menu \"mais\" (…)"
            ],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ux/tabs; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "sincronizar-aba-com-a-url",
            "nome": "Sincronizar aba com a URL",
            "descricao": "Reflete a aba ativa na URL para deep-link, favoritar, compartilhar e usar voltar/avançar do navegador.",
            "controle": "select",
            "opcoes": [
                "Hash (#aba)",
                "Query (?tab=)"
            ],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ux/tabs; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "lembrar-ltima-aba",
            "nome": "Lembrar última aba",
            "descricao": "Persiste a última aba aberta em localStorage e a restaura automaticamente no próximo acesso.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ux/tabs; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "carregamento-tardio-do-painel",
            "nome": "Carregamento tardio do painel",
            "descricao": "Adia render/fetch do conteúdo até a aba ser ativada pela 1ª vez — ideal para painéis pesados ou via AJAX.",
            "controle": "select",
            "opcoes": [
                "Renderizar ao ativar",
                "Buscar via AJAX",
                "Sempre recarregar"
            ],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ux/tabs; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "prote-o-de-edi-o-n-o-salva",
            "nome": "Proteção de edição não salva",
            "descricao": "Marca com ponto (•) as abas com edições pendentes e pede confirmação antes de trocar de painel em edição.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ux/tabs; comportamento via controller Stimulus. Não altera a base."
        }
    ],
    "snippet_uso": "<twig:Tabs>…</twig:Tabs>",
    "exemplo_demo": "<twig:Tabs defaultValue=\"overview\" class=\"w-[400px]\">\n    <twig:Tabs:List>\n        <twig:Tabs:Trigger value=\"overview\">Overview</twig:Tabs:Trigger>\n        <twig:Tabs:Trigger value=\"analytics\">Analytics</twig:Tabs:Trigger>\n        <twig:Tabs:Trigger value=\"reports\">Reports</twig:Tabs:Trigger>\n        <twig:Tabs:Trigger value=\"settings\">Settings</twig:Tabs:Trigger>\n    </twig:Tabs:List>\n    <twig:Tabs:Content value=\"overview\">\n        <twig:Card>\n            <twig:Card:Header>\n                <twig:Card:Title>Overview</twig:Card:Title>\n                <twig:Card:Description>\n                    View your key metrics and recent project activity. Track progress\n                    across all your active projects.\n                </twig:Card:Description>\n            </twig:Card:Header>\n            <twig:Card:Content class=\"text-muted-foreground text-sm\">\n                You have 12 active projects and 3 pending tasks.\n            </twig:Card:Content>\n        </twig:Card>\n    </twig:Tabs:Content>\n    <twig:Tabs:Content value=\"analytics\">\n        <twig:Card>\n            <twig:Card:Header>\n                <twig:Card:Title>Analytics</twig:Card:Title>\n                <twig:Card:Description>\n                    Track performance and user engagement metrics. Monitor trends and\n                    identify growth opportunities.\n                </twig:Card:Description>\n            </twig:Card:Header>\n            <twig:Card:Content class=\"text-muted-foreground text-sm\">\n                Page views are up 25% compared to last month.\n            </twig:Card:Content>\n        </twig:Card>\n    </twig:Tabs:Content>\n    <twig:Tabs:Content value=\"reports\">\n        <twig:Card>\n            <twig:Card:Header>\n                <twig:Card:Title>Reports</twig:Card:Title>\n                <twig:Card:Description>\n                    Generate and download your detailed reports. Export data in\n                    multiple formats for analysis.\n                </twig:Card:Description>\n            </twig:Card:Header>\n            <twig:Card:Content class=\"text-muted-foreground text-sm\">\n                You have 5 reports ready and available to export.\n            </twig:Card:Content>\n        </twig:Card>\n    </twig:Tabs:Content>\n    <twig:Tabs:Content value=\"settings\">\n        <twig:Card>\n            <twig:Card:Header>\n                <twig:Card:Title>Settings</twig:Card:Title>\n                <twig:Card:Description>\n                    Manage your account preferences and options. Customize your\n                    experience to fit your needs.\n                </twig:Card:Description>\n            </twig:Card:Header>\n            <twig:Card:Content class=\"text-muted-foreground text-sm\">\n                Configure notifications, security, and themes.\n            </twig:Card:Content>\n        </twig:Card>\n    </twig:Tabs:Content>\n</twig:Tabs>",
    "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": "Congelados e imutáveis: tipografia (text-sm, font-medium), cantos (rounded-lg na List, rounded-md no Trigger), espaçamento (p-[3px], gaps), cores (bg-muted, text-muted-foreground/foreground), altura h-8, as duas variantes visuais default/line e a orientação horizontal/vertical (props da base), os slots de ícone inline-start/inline-end já previstos no Trigger, e toda a a11y — role=tablist/tab/tabpanel, aria-selected/controls/labelledby, foco visível (ring), estado disabled e suporte RTL/LTR. por isso orientação, variantes e ícone NÃO entram como enrichers (são base)",
    "mcp": {
        "tool": "get_component",
        "args": {
            "id": "tabs"
        }
    }
}
  1. v0.1.0 Camada de IA: scaffold de página + specs íntegras
    • Novo tool MCP get_page_scaffold: devolve a MOLDURA de uma página nova (layout + blocks reais, contrato do renderPage, receita de rota + buildNav, tokens de layout lidos de app.css e snippet .html.twig válido) — dá pra montar página sem ler o controller/layout.
    • Fonte única do scaffold em config/ds-specs/_page-scaffold.json (padrão v1.0); tokens semânticos derivados de assets/styles/app.css em runtime.
    • Fix: exemplo_demo estava truncado em 1600 bytes em 5 specs (card, field, table, tabs, typography) — reconstituídos íntegros a partir dos demos, fechando todas as tags.
    • Nova seção Updates (este changelog versionado) como 9º eixo do shell.
    • Docs: CLAUDE.md e AI-LAYER.md citam o novo tool; contadores de tools atualizados (6 → 7).

Changelog completo em Updates.