Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Components

Free

Hover Card for React

Open a small preview when the pointer rests on a link, and keep it open so someone can move into the card. For React with Base UI, when a tooltip is too short.

Framework
UI library

The card opens on hover and stays up so the pointer can move inside. People can select the text in it.

Use it for a preview that takes more than a glance, like a handle and a short bio. A Tooltip is enough for a few words on an icon button. In React, Base UI waits briefly before closing so the pointer can cross into the card.

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

Anatomy

Hover Card anatomy: trigger, positioner, arrow, content
HoverCardArrow
└── HoverCardArrowTip
HoverCardTrigger
HoverCardContent
└── HoverCardPositioner

Usage

import { Button } from "@/components/ui/button";
import {
  HoverCard, HoverCardContent, HoverCardTrigger,
} from "@/components/ui/hover-card";
const HoverCardDemo = () => (
  <HoverCard>
    <HoverCardTrigger
      closeDelay={100}
      delay={10}
      render={<Button variant="link" />}
    >
      Hover Here
    </HoverCardTrigger>
    <HoverCardContent className="flex w-64 max-w-full flex-col gap-0.5">
      <div className="font-semibold">@nextjs</div>
      <div>The React Framework – created and maintained by @vercel.</div>
      <div className="mt-1 text-muted-foreground text-xs">
        Joined December 2021
      </div>
    </HoverCardContent>
  </HoverCard>
);

Accessibility

Tab
Opens the hover card once focus reaches the trigger, after the open delay. Closes it when focus leaves.
Escape
If open, closes the hover card.
Enter
Activate the focused item.
Space
Activate the focused control.

Demos

Sides

Four buttons open the same card on the left, top, bottom, and right, and each card says which side it used. The open and close delays are short here so you can move between them. Pin a side when the default would cover the link the person is reading. Leave it unset when there is room for the card to flip on its own.

Preview width

Rtl

The card is a product preview in Arabic, wireless headphones and a price, opened from buttons for each physical side. A second row is labeled as the start and the end of the line. Direction is set on the wrapper and again on the card, so the price and the title align with the page instead of hugging the wrong edge.

Preview width

FAQ

How do I control whether a Hover Card is open in React?

Leave the card uncontrolled and it opens from hover and keyboard focus, then closes after the pointer and focus leave. Control it when another part of the screen must force it open or closed, using defaultOpen only for the first state, because the close delay is what lets the pointer move into the content. Pass open, and onOpenChange receives the next boolean.

How do I choose which side a Hover Card appears on with Base UI?

The Sides demo places the card on the left, top, bottom, or right, and the content is portaled and stacked at z-50 so overflow on a parent does not clip it. A longer close delay, measured in milliseconds, makes the card easier to reach. Set side on HoverCardContent, and set delay and closeDelay on HoverCardTrigger, with align, sideOffset, and alignOffset adjusting the position.

How do I use a button as the Hover Card trigger in React?

The trigger must be focusable, or keyboard users cannot open the card, so a Button or a link is the right host. The card then opens from hover and from focus, and Escape closes it, as the Accessibility section describes. Do not put the preview text inside the trigger label. Pass render a Button on HoverCardTrigger, do not use asChild, and use HoverCardContent as the popup.

Can I open a Hover Card from the keyboard?

Yes, focus opens a Hover Card after the delay, and moving focus away closes it, while Escape dismisses an open card. The Accessibility section also lists Enter and Space for activating the focused control. On a touch screen there is no hover, so use a Popover when the preview must open from a tap and stay until dismissed.

Should I use a Hover Card or a Tooltip?

Use a Hover Card for a preview people can move the pointer into, such as a profile card. Use a Tooltip for a short label on an icon button. Use a Hint for a small note that stays inside its parent. Use a Popover when the surface should open on click instead of hover.

How do I install Hover Card?

Run the command in the Installation section above. It adds Hover Card, its trigger, and its content to your ui folder. Install from that section rather than pasting a partial tree, so the positioning parts stay together, and check the Anatomy section for the arrow and positioner on the builds that render them. The command uses the shadcn CLI.

Why does a Hover Card close before I can read it?

The pointer left the trigger before the close delay elapsed, so the Hover Card shut, and raising the close delay gives the pointer time to cross the gap into the content. The open delay is the wait before it appears, which avoids flashing while the pointer passes by. Both are milliseconds, and the side question above says which component receives them.

API Reference

HoverCard

data-slot="hover-card"

PropType
open?boolean

Whether the preview card is currently open.

defaultOpen?boolean

Whether the preview card is initially open. To render a controlled preview card, use the open prop instead.

Default
false
onOpenChange?(open: boolean, eventDetails: PreviewCardRoot.ChangeEventDetails) → void

Event handler called when the preview card is opened or closed.

Type
(open: boolean, eventDetails: PreviewCardRoot.ChangeEventDetails) → void
Parameters

open – boolean

eventDetails – PreviewCardRoot.ChangeEventDetails

Returns
void
actionsRef?React.RefObject<PreviewCardRoot.Actions | null>

A ref to imperative actions. - unmount: Ends the closing phase of the preview card after an externally controlled closing animation finishes. Call preventUnmountOnClose() in onOpenChange first, otherwise the preview card completes closing on its own. Whether it leaves the DOM is decided by keepMounted on the portal. - close: Closes the preview card imperatively when called.

Type
React.RefObject<PreviewCardRoot.Actions | null>
children?React.ReactNode | PayloadChildRenderFunction<Payload>

The content of the preview card. This can be a regular React node or a render function that receives the payload of the active trigger.

Type
React.ReactNode | PayloadChildRenderFunction<Payload>
defaultTriggerId?string | null

ID of the trigger that the preview card is associated with. This is useful in conjunction with the defaultOpen prop to create an initially open preview card.

Type
string | null
handle?PreviewCardHandle<Payload>

A handle to associate the preview card with a trigger. If specified, allows external triggers to control the card's open state. Can be created with the PreviewCard.createHandle() method.

Type
PreviewCardHandle<Payload>
onOpenChangeComplete?(open: boolean) → void

Event handler called after any animations complete when the preview card is opened or closed.

Parameters

open – boolean

Returns
void
triggerId?string | null

ID of the trigger that the preview card is associated with. This is useful in conjunction with the open prop to create a controlled preview card. There's no need to specify this prop when the preview card is uncontrolled (that is, when the open prop is not set).

Type
string | null
render?ReactElement | ((props: object, state: object) => ReactElement)

Replace the host element or compose it with another component.

Type
ReactElement | ((props: object, state: object) => ReactElement)

HoverCardTrigger

<a> data-slot="hover-card-trigger"

PropType
closeDelay?number

How long to wait before closing the preview card. Specified in milliseconds.

Default
300
delay?number

How long to wait before the preview card opens. Specified in milliseconds.

Default
600
handle?PreviewCardHandle<Payload>

A handle to associate the trigger with a preview card.

Type
PreviewCardHandle<Payload>
payload?Payload

A payload to pass to the preview card when it is opened.

render?ReactElement | ((props: object, state: object) => ReactElement)

Replace the host element or compose it with another component.

Type
ReactElement | ((props: object, state: object) => ReactElement)

HoverCardContent

<div> data-slot="hover-card-content"

PropType
render?ReactElement | ((props: object, state: object) => ReactElement)

Replace the host element or compose it with another component.

Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string

Merged with the part's classes.

CSS variableType
--transform-originstring

Where the content scales from, on its trigger's side.

With other components

  • Free

    Avatar

    Media

    Face in the preview

  • Free

    Button

    Buttons

    Link-style trigger

  • Free

    Badge

    Feedback

    Role next to the name

  • Free

    Separator

    Layout

    Split bio from stats

  • Free

    Skeleton

    Feedback

    While the profile loads

  • Free

    Image in the preview