Pular para o conteúdo

Hover Card

templates/components/HoverCard

É um overlay de "espiada": revela conteúdo rico e suplementar (prévia de perfil, definição, metadados) ancorado a um gatilho, disparado por HOVER/FOCO — nunca por clique. Sua natureza gira em torno de tempo (delay para não piscar), lugar (posição relativa ao gatilho) e a travessia do cursor até o card.

Base congelada

Conteúdo

Lado de exibição

Face do gatilho onde o card…

Face do gatilho onde o card aparece: acima, abaixo, à esquerda ou à direita. posicionável

Alinhamento ao gatilho

Ancora o card ao início, centro…

Ancora o card ao início, centro ou fim do gatilho ao longo do lado escolhido, para casar com gatilhos largos/estreitos.

Reposicionar para caber (auto-flip)

Se o lado preferido estourar a…

Se o lado preferido estourar a viewport, vira automaticamente para o lado oposto para não cortar o card nas bordas da tela.

Seta apontadora

Caret aditivo ligando o card ao…

Caret aditivo ligando o card ao gatilho para indicar de onde ele saiu; herda bg-popover/ring e acompanha o lado escolhido.

Comportamento

Atraso de intenção (abrir/fechar)

Tempo em ms antes de mostrar…

Tempo em ms antes de mostrar e antes de ocultar (openDelay/closeDelay); filtra passagens acidentais do mouse e evita piscar.

Ponte de hover (área segura)

Mantém o card aberto enquanto o…

Mantém o card aberto enquanto o cursor atravessa o vão entre gatilho e card, evitando o fechamento no meio do caminho pela diagonal.

Fixar ao clicar

Clicar no gatilho trava o card…

Clicar no gatilho trava o card aberto para ler, copiar ou clicar links do conteúdo sem ele fechar ao tirar o mouse; toque fora ou ESC solta.

Carregar conteúdo sob demanda

Busca o conteúdo do card via…

Busca o conteúdo do card via requisição no primeiro hover (ex.: prévia de perfil/registro), mostrando estado de carregando e cacheando nas próximas vezes.

Abrir por toque (sem hover)

Em dispositivos sem hover (toque), o…

Em dispositivos sem hover (toque), o primeiro toque no gatilho abre o card e um toque fora o fecha, cobrindo o cenário em que hover não existe.
Código gerado

Cole no Claude Code — ele acerta de primeira.

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

BASE CONGELADA (não mude por instância): A aparência do card é imutável: largura w-64, cantos rounded-lg, cor bg-popover/text-popover-foreground, padding interno p-2.5, tipografia text-sm, shadow-md, contorno ring-1, camada z-50, estado inicial fechado, semântica role="tooltip" e disparo por mouseenter/mouseleave + focus/blur com trigger tabindex=0. Os enriquecedores só mexem em tempo, posicionamento, comportamento de abertura/permanência e conteúdo aditivo — nunca em fonte, cor, cantos ou espaçamento interno do card.

USO: <twig:HoverCard />

CAPACIDADES OPT-IN (ligue sem alterar o visual):
- Atraso de intenção (abrir/fechar): Tempo em ms antes de mostrar e antes de ocultar (openDelay/closeDelay); filtra passagens acidentais do mouse e evita piscar. [number]- Lado de exibição: Face do gatilho onde o card aparece: acima, abaixo, à esquerda ou à direita. [position → Acima / Abaixo / Esquerda / Direita]- Alinhamento ao gatilho: Ancora o card ao início, centro ou fim do gatilho ao longo do lado escolhido, para casar com gatilhos largos/estreitos. [select → Início / Centro / Fim]- Reposicionar para caber (auto-flip): Se o lado preferido estourar a viewport, vira automaticamente para o lado oposto para não cortar o card nas bordas da tela. [toggle]- Ponte de hover (área segura): Mantém o card aberto enquanto o cursor atravessa o vão entre gatilho e card, evitando o fechamento no meio do caminho pela diagonal. [toggle]- Fixar ao clicar: Clicar no gatilho trava o card aberto para ler, copiar ou clicar links do conteúdo sem ele fechar ao tirar o mouse; toque fora ou ESC solta. [toggle]- Carregar conteúdo sob demanda: Busca o conteúdo do card via requisição no primeiro hover (ex.: prévia de perfil/registro), mostrando estado de carregando e cacheando nas próximas vezes. [toggle]- Seta apontadora: Caret aditivo ligando o card ao gatilho para indicar de onde ele saiu; herda bg-popover/ring e acompanha o lado escolhido. [toggle]- Abrir por toque (sem hover): Em dispositivos sem hover (toque), o primeiro toque no gatilho abre o card e um toque fora o fecha, cobrindo o cenário em que hover não existe. [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): 5, tipografia text-sm, shadow-md, contorno ring-1, camada z-50, estado inicial fechado, semântica role="tooltip" e disparo por mouseenter/mouseleave + focus/blur com trigger tabindex=0

Via MCP: tool get_component com {"id": "hover-card"} · list_capabilities("hover-card").

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

Spec machine-readable (JSON)

{
    "$schema_version": "1.0",
    "id": "hover-card",
    "component": "HoverCard",
    "eixo": "ux",
    "particularidade": "É um overlay de \"espiada\": revela conteúdo rico e suplementar (prévia de perfil, definição, metadados) ancorado a um gatilho, disparado por HOVER/FOCO — nunca por clique. Sua natureza gira em torno de tempo (delay para não piscar), lugar (posição relativa ao gatilho) e a travessia do cursor até o card.",
    "base_congelada": "A aparência do card é imutável: largura w-64, cantos rounded-lg, cor bg-popover/text-popover-foreground, padding interno p-2.5, tipografia text-sm, shadow-md, contorno ring-1, camada z-50, estado inicial fechado, semântica role=\"tooltip\" e disparo por mouseenter/mouseleave + focus/blur com trigger tabindex=0. Os enriquecedores só mexem em tempo, posicionamento, comportamento de abertura/permanência e conteúdo aditivo — nunca em fonte, cor, cantos ou espaçamento interno do card.",
    "props": [
        {
            "name": "openDelay",
            "type": "number",
            "default": "0",
            "description": "Delay in milliseconds before showing the content. Defaults to `0` #}"
        },
        {
            "name": "closeDelay",
            "type": "number",
            "default": "0",
            "description": "Delay in milliseconds before hiding the content. Defaults to `0` #}"
        }
    ],
    "capacidades": [
        {
            "id": "atraso-de-inten-o-abrir-fechar",
            "nome": "Atraso de intenção (abrir/fechar)",
            "descricao": "Tempo em ms antes de mostrar e antes de ocultar (openDelay/closeDelay); filtra passagens acidentais do mouse e evita piscar.",
            "controle": "number",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (number). Ligue no configurador em /vitrine/ux/hover-card; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "lado-de-exibi-o",
            "nome": "Lado de exibição",
            "descricao": "Face do gatilho onde o card aparece: acima, abaixo, à esquerda ou à direita.",
            "controle": "position",
            "opcoes": [
                "Acima",
                "Abaixo",
                "Esquerda",
                "Direita"
            ],
            "posicionavel": true,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (position). Ligue no configurador em /vitrine/ux/hover-card; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "alinhamento-ao-gatilho",
            "nome": "Alinhamento ao gatilho",
            "descricao": "Ancora o card ao início, centro ou fim do gatilho ao longo do lado escolhido, para casar com gatilhos largos/estreitos.",
            "controle": "select",
            "opcoes": [
                "Início",
                "Centro",
                "Fim"
            ],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (select). Ligue no configurador em /vitrine/ux/hover-card; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "reposicionar-para-caber-auto-flip",
            "nome": "Reposicionar para caber (auto-flip)",
            "descricao": "Se o lado preferido estourar a viewport, vira automaticamente para o lado oposto para não cortar o card nas bordas da tela.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ux/hover-card; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "ponte-de-hover-rea-segura",
            "nome": "Ponte de hover (área segura)",
            "descricao": "Mantém o card aberto enquanto o cursor atravessa o vão entre gatilho e card, evitando o fechamento no meio do caminho pela diagonal.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ux/hover-card; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "fixar-ao-clicar",
            "nome": "Fixar ao clicar",
            "descricao": "Clicar no gatilho trava o card aberto para ler, copiar ou clicar links do conteúdo sem ele fechar ao tirar o mouse; toque fora ou ESC solta.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ux/hover-card; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "carregar-conte-do-sob-demanda",
            "nome": "Carregar conteúdo sob demanda",
            "descricao": "Busca o conteúdo do card via requisição no primeiro hover (ex.: prévia de perfil/registro), mostrando estado de carregando e cacheando nas próximas vezes.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ux/hover-card; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "seta-apontadora",
            "nome": "Seta apontadora",
            "descricao": "Caret aditivo ligando o card ao gatilho para indicar de onde ele saiu; herda bg-popover/ring e acompanha o lado escolhido.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ux/hover-card; comportamento via controller Stimulus. Não altera a base."
        },
        {
            "id": "abrir-por-toque-sem-hover",
            "nome": "Abrir por toque (sem hover)",
            "descricao": "Em dispositivos sem hover (toque), o primeiro toque no gatilho abre o card e um toque fora o fecha, cobrindo o cenário em que hover não existe.",
            "controle": "toggle",
            "opcoes": [],
            "posicionavel": false,
            "e_funcao": true,
            "como_plugar": "Capacidade opt-in (toggle). Ligue no configurador em /vitrine/ux/hover-card; comportamento via controller Stimulus. Não altera a base."
        }
    ],
    "snippet_uso": "<twig:HoverCard />",
    "exemplo_demo": "<twig:HoverCard openDelay=\"10\" closeDelay=\"100\">\n    <twig:HoverCard:Trigger>\n        <twig:Button variant=\"link\" {{ ...hover_card_trigger_attrs }}>Hover Here</twig:Button>\n    </twig:HoverCard:Trigger>\n    <twig:HoverCard:Content class=\"flex w-64 flex-col gap-0.5\">\n        <div class=\"font-semibold\">@symfony</div>\n        <div>The PHP framework for web applications — created by @fabpot.</div>\n        <div class=\"mt-1 text-xs text-muted-foreground\">Joined October 2010</div>\n    </twig:HoverCard:Content>\n</twig:HoverCard>",
    "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": "5, tipografia text-sm, shadow-md, contorno ring-1, camada z-50, estado inicial fechado, semântica role=\"tooltip\" e disparo por mouseenter/mouseleave + focus/blur com trigger tabindex=0",
    "mcp": {
        "tool": "get_component",
        "args": {
            "id": "hover-card"
        }
    }
}