Skip to content

Pickers and overlays

Preview

A rich card revealed by pausing on a link.

When to use it: Use it to show what a link leads to, such as a profile or package card.

On this page

Example

Loading example…
Preview.tsxtsx
import { Preview, PreviewPopover, PreviewTrigger } from "@comp0/react";

export function Example() {
  return (
    <Preview>
      <PreviewTrigger
        href="https://www.npmjs.com/package/@comp0/react"
        className="text-base text-zinc-800 underline decoration-zinc-400 underline-offset-4 hover:decoration-zinc-800 sm:text-sm dark:text-zinc-100 dark:decoration-zinc-500 dark:hover:decoration-zinc-200"
      >
        @comp0/react on npm
      </PreviewTrigger>
      <PreviewPopover
        placement="bottom start"
        offset={8}
        className="flex w-64 flex-col gap-2 rounded border-0 bg-white p-3 opacity-100 shadow-lg ring-1 ring-zinc-950/10 transition-opacity duration-150 ease-out starting:opacity-0 motion-reduce:transition-none dark:bg-zinc-900 dark:shadow-none dark:ring-white/10"
      >
        <p className="text-base font-medium text-zinc-900 sm:text-sm dark:text-zinc-100">
          @comp0/react
        </p>
        <p className="text-base text-zinc-600 sm:text-sm dark:text-zinc-400">
          Headless React components with native-first behavior and styling hooks.
        </p>
        <dl className="flex gap-4 text-base text-zinc-600 sm:text-sm dark:text-zinc-400">
          <div className="flex gap-1">
            <dt>Version</dt>
            <dd className="font-medium text-zinc-900 dark:text-zinc-100">0.1.0</dd>
          </div>
          <div className="flex gap-1">
            <dt>Weekly</dt>
            <dd className="font-medium text-zinc-900 dark:text-zinc-100">12k</dd>
          </div>
        </dl>
      </PreviewPopover>
    </Preview>
  );
}

Anatomy

Dashed frames are invisible state providers; shaded shapes own real DOM. Numbered pins match the list below.

A wireframe sketch of the assembled component. Each numbered marker matches a part in the list that follows.

  1. Preview

    Open-state provider with hover-intent timing. Does not add a DOM element.

  2. PreviewTrigger

    Link that reveals the card on hover intent or focus. Owns a DOM element.

  3. PreviewPopover

    Rich card that may hold interactive content. Owns a DOM element.

Step by step

  1. 1

    Add the main part

    Start Preview around the link people already follow.

  2. 2

    Add the supporting parts

    Give PreviewTrigger the real href and put the card in PreviewPopover with a placement.

  3. 3

    Make the behavior clear

    Keep the link useful on its own; the card is a bonus, not the destination.

    Exampletsx
    <Preview>
      <PreviewTrigger href="/users/ada">@ada</PreviewTrigger>
      <PreviewPopover placement="bottom start" offset={8}>
        Ada Lovelace, first programmer
      </PreviewPopover>
    </Preview>;

Keyboard

Focus reveals the card on its trigger.
Esc
Closes the card.

Forms and accessibility

Previews never hold form values; they only describe what a link leads to.

Accessibility checklist

  • Keep the trigger a real link with a clear name; the card must stay optional.
  • Do not put content in the card that is not reachable another way.
  • Escape closes the card from anywhere, and it stays open while hovered or focused (WCAG 1.4.13).

API reference

Importtsx
import { Preview, PreviewPopover, PreviewTrigger } from "@comp0/react";

Preview

Context only

Open-state provider with hover-intent timing.

PropTypeDescription
openbooleanControlled open state.
defaultOpenbooleanInitial open state.
onToggle(open: boolean) => voidReceives the next open state.
openDelaynumberMilliseconds the pointer must rest before opening; 600 by default. Focus opens immediately.
closeDelaynumberMilliseconds after the pointer or focus leaves before closing; 300 by default.

PreviewTrigger

DOM element

Link that reveals the card on hover intent or focus.

PropTypeDescription
hrefstringReal destination; the preview never replaces it.
asElementType | FragmentFragment merges the trigger onto your own element child.

PreviewPopover

DOM element

Rich card that may hold interactive content.

PropTypeDescription
placementPopoverPlacementTrigger side to open on, such as "bottom start"; flips when there is no room.
offsetnumberPixel gap between the trigger and the card.

Style hooks

Attributes that appear while a state is true. Target them with Tailwind data variants such as data-open:bg-zinc-100, or with any CSS selector.

PreviewTrigger

Style hookMeaning
[data-open]The card is visible.

PreviewPopover

Style hookMeaning
[data-open]The card is visible.

Keep exploring