Skip to main content
View Zag.js on Github
Join the Discord server

Hover Card

An hover card allows sighted users to preview content available behind a link



  • Customize side, alignment, offsets
  • Optionally render a pointing arrow.
  • Supports custom open and close delays.
  • Opens on hover only.
  • Ignored by screen readers.


To use the hover card machine in your project, run the following command in your command line:

npm install @zag-js/hover-card @zag-js/react # or yarn add @zag-js/hover-card @zag-js/react

This command will install the framework agnostic hover card logic and the reactive utilities for your framework of choice.


To set up the hover card correctly, you'll need to understand its anatomy and how we name its parts.

Each part includes a data-part attribute to help identify them in the DOM.

On a high level, the hover card consists of:

  • Trigger: The trigger for the Hover Card - Usually a link.
  • Positioner: The element that positions the hover card.
  • Content: The container for the hover card's content.


First, import the hover card package into your project

import * as hoverCard from "@zag-js/hover-card"

The hover card package exports two key functions:

  • machine — The state machine logic for the hover card widget.
  • connect — The function that translates the machine's state to JSX attributes and event handlers.

Next, import the required hooks and functions for your framework and use the hover-card machine in your project 🔥

import * as hoverCard from "@zag-js/hover-card" import { useMachine, normalizeProps, Portal } from "@zag-js/react" function HoverCard() { const [state, send] = useMachine(hoverCard.machine({ id: "1" })) const api = hoverCard.connect(state, send, normalizeProps) return ( <> <a href="" target="_blank" {...api.triggerProps} > Twitter </a> {api.isOpen && ( <Portal> <div {...api.positionerProps}> <div {...api.contentProps}> <div {...api.arrowProps}> <div {...api.arrowTipProps} /> </div> Twitter Preview </div> </div> </Portal> )} </> ) }

Making it opened initially

To make an hover card open by default, set the context's open property to true

const [state, send] = useMachine( hoverCard.machine({ open: true, }), )

Listening for open state changes

When the hover card is opened or closed, the onOpenChange callback is invoked.

const [state, send] = useMachine( hoverCard.machine({ onOpenChange(details) { // details => { open: boolean } console.log("hovercard is:", ? "opened" : "closed") }, }), )

Styling guide

Earlier, we mentioned that each hover card part has a data-part attribute added to them to select and style them in the DOM.

[data-part="trigger"] { /* styles for trigger */ } [data-part="content"] { /* styles for content */ }

Open and closed state

The hover card exposes a data-state attribute that can be used to style the hover card based on its open-close state.

[data-part="trigger"][data-state="open|closed"] { /* styles for open or closed state */ } [data-part="content"][data-state="open|closed"] { /* styles for open or closed state */ }


Zag exposes some variable that can be used to style the arrow.

[data-part="arrow"] { /* styles for arrow */ --arrow-background: white; --arrow-size: 8px; }
[data-part="content"] { /* styles for content */ }

Methods and Properties

The hover card's api method exposes the following methods:

  • isOpenbooleanWhether the hover card is open
  • open() => voidFunction to open the hover card
  • close() => voidFunction to close the hover card
  • setPositioning(options?: Partial<PositioningOptions>) => voidFunction to reposition the popover

Edit this page on GitHub

On this page