KDS
Overlays

HoverCard

Preview rico em hover — sem interatividade dentro, sem informação crítica.

Overview

HoverCard mostra um preview rico ao pairar o mouse — perfil de usuário em @mentions, preview de link, teaser de imagem. É o que acontece quando você passa o cursor sobre um username no Twitter ou um link no Notion.

Hover é discoverable mas opcional. Touch users não conseguem disparar; keyboard users abrem só quando o foco passa pelo trigger. Isso significa: nada crítico aqui dentro. Conteúdo do HoverCard deve ser sempre acessível por outro caminho — clicar no link abre a página inteira, etc.

Preview
HoverCard com profile preview.

Anatomy

<HoverCard>
  <HoverCardTrigger />
  <HoverCardContent>
    {/* preview content */}
  </HoverCardContent>
</HoverCard>

Subcomponents

ComponenteDescrição
HoverCardRaiz que controla open via hover.
HoverCardTriggerElemento que dispara o preview ao pairar.
HoverCardContentContainer portalado com o preview.

Usage

import {
  HoverCard,
  HoverCardTrigger,
  HoverCardContent
} from "@kalvner/kds/overlays/hover-card";

export function UserMention({ user }) {
  return (
    <HoverCard>
      <HoverCardTrigger asChild>
        <a href={`/u/${user.handle}`}>@{user.handle}</a>
      </HoverCardTrigger>
      <HoverCardContent className="w-72">
        {/* user info preview */}
      </HoverCardContent>
    </HoverCard>
  );
}

When to use

  • Profile previews em menções, listas de membros.
  • Link previews — small image + title + description, estilo Notion / Slack.
  • Detalhes complementares de uma imagem ou documento sem precisar abrir a página.

When not to use

  • Para informação crítica — se o usuário precisa ler para agir, não pode estar num hover. Use Popover (clique intencional) ou imprima na própria página.
  • Para conteúdo interativo — botões / inputs dentro de HoverCard ficam difíceis de alcançar (o hover dispara/some). Use Popover.
  • Em mobile / touch — touch users não disparam HoverCard.

Best practices

  • Delay padrão. Open delay de ~700ms evita flicker quando o cursor só passa por cima. Fechar com leve atraso evita que o preview suma quando o usuário tenta clicar dentro.
  • Largura modesta. Default 256px (w-64). Previews são teaser, não páginas — se a content estiver pedindo 500px de largura, o caso pertence ao Popover ou a uma página dedicada.
  • Sem botões dentro. O comportamento de hover faz com que botões apareçam/sumam de forma frágil. Se você precisa de "Ver perfil", o trigger inteiro já é o link.
  • Não auto-foque. Ao contrário do Dialog, HoverCard não rouba foco — ele complementa, não interrompe.

Accessibility

ConcernComportamento
RolesRadix aplica role="dialog" (com aria-haspopup) embora seja efêmero.
FocoFoco no trigger dispara abrir; sair do trigger fecha. Foco não entra no content.
KeyboardTab para o trigger abre. Esc fecha. Não há navegação para dentro do content.
Screen readerO content é anunciado quando aberto via foco. Para conteúdo verdadeiramente crítico, prefira mostrar inline ou em Popover.
TouchSem trigger natural — design para que touch users tenham acesso ao mesmo conteúdo via clique.
Reduced motionFade respeita prefers-reduced-motion.
  • Popover — para conteúdo interativo (clique).
  • Tooltip — para labels curtos e simples.
  • Avatar — frequente companheiro em profile previews.

On this page