Overlays

HoverCard

A preview of where a link goes, shown when a mouse rests on the link or the keyboard focuses it: a cook's profile, a recipe's summary. It shows only on devices that can hover and never after a touch, so the link must work without it.

Shakshuka by Ari Mendelow

Install

Once per app, with Tailwind CSS v4 and an @/* path alias (Ouro HX is built on Base UI, so --base base; skip -t in an existing app):

npx shadcn@latest init --base base --preset nova --yes --no-monorepo
npx shadcn@latest add ourostack/ouro-ui/ouro-base#v1.2.13

Then the component. From v0.8.0 it installs only the helpers it imports and never touches your stylesheet (Installing):

npx shadcn@latest add ourostack/ouro-ui/hover-card#v1.2.13

Or, with the @ouro namespace set up:

npx shadcn@latest add @ouro/ouro-base @ouro/hover-card

Its tests, stories and Playwright spec are optional. They need Vitest 4.1.11 or later, and from v0.8.0 never change a version your app has (Testing):

npx shadcn@latest add ourostack/ouro-ui/hover-card#v1.2.13 ourostack/ouro-ui/hover-card-tests#v1.2.13
import { HoverCard } from "@/components/ouro/hover-card/hover-card";

Paths use shadcn's default @/ alias; the CLI rewrites them to yours.

Example

<HoverCard trigger={<Link href="/cooks/ari">Ari Mendelow</Link>}>
  <CookSummary cook={ari} />
</HoverCard>

Usage

It stacks above the page at --ouro-layer, a z-index of 50 by default (from ouro-base.css), like Dialog and Sheet.

Use instead when

  • Use Tooltip instead for a short label, and Popover for anything the user needs or acts on, since a Popover opens on tap.

Props

Type: HoverCardProps.

align
Type: "start" | "center" | "end"
Default: "center"
How the card lines up with the link along that side.
children (required)
Type: ReactNode
The preview: a few lines about where the link goes. Only what the user can do without; put controls elsewhere.
className
Type: string
Layout only, applied to the card: width (18rem, w-72, by default) and padding. Your classes win over Ouro UI's. Appearance classes warn in development.
side
Type: "top" | "bottom" | "left" | "right"
Default: "bottom"
The side of the link the card sits on; it flips when there is no room.
trigger (required)
Type: ReactElement
The link the card previews: trigger={<Link href="/cooks/ari">Ari</Link>}. It works on its own: touch users, and devices that cannot hover, get only the link.

Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

  • closeDelay: Not a prop. Ouro UI sets the delays: <HoverCard trigger={…}>.
  • content: Not a prop. The preview is the children: <HoverCard trigger={…}>…</HoverCard>.
  • openDelay: Not a prop. Ouro UI sets the delays: <HoverCard trigger={…}>.
  • placement: Not a prop. Ouro UI splits placement into side and align: <HoverCard side="bottom" align="start">.

className is for layout only

Pass margins, width and grid placement (mt-4, w-full, col-span-2). Your classes always win over Ouro UI's: HoverCard merges className last with cn (tailwind-merge), so a class that conflicts with its own replaces it.layout-classes

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (hover:, sm:) and any ! are removed, it starts with bg-, text-, border-, rounded-, shadow-, font-, ring-, from-, via-, to-, fill- or stroke-, or is border, rounded, shadow or ring, or has a dark: variant. Text wrapping, overflow and table layout classes (text-wrap, text-ellipsis, border-collapse) are layout and do not warn.

Alignment classes (text-center) warn too: use the align prop.

Claim sources