# Hover Card

URL: https://ark-ui.com/docs/components/hover-card
LLM: https://ark-ui.com/llms.txt/components/hover-card

A card that appears when a user hovers over an element.

---



## Anatomy



```tsx
<HoverCard.Root>
  <HoverCard.Trigger />
  <HoverCard.Positioner>
    <HoverCard.Arrow>
      <HoverCard.ArrowTip />
    </HoverCard.Arrow>
    <HoverCard.Content />
  </HoverCard.Positioner>
</HoverCard.Root>
```

## Examples

```tsx
import { HoverCard } from '@ark-ui/react/hover-card'
import { Portal } from '@ark-ui/react/portal'
import styles from 'styles/hover-card.module.css'

export const Basic = () => (
  <HoverCard.Root>
    <p>
      Liked by{' '}
      <HoverCard.Trigger className={styles.Trigger} asChild>
        <a href="#profile">@sarah_chen</a>
      </HoverCard.Trigger>{' '}
      and 3 others
    </p>
    <Portal>
      <HoverCard.Positioner>
        <HoverCard.Content className={styles.Content}>
          <HoverCard.Arrow className={styles.Arrow}>
            <HoverCard.ArrowTip className={styles.ArrowTip} />
          </HoverCard.Arrow>
          <div className={styles.Body}>
            <div className={styles.Header}>
              <img className={styles.Avatar} src="https://i.pravatar.cc/300?u=sarah" alt="Sarah Chen" />
              <button type="button" className={styles.FollowButton}>
                Follow
              </button>
            </div>
            <div>
              <p className={styles.Name}>Sarah Chen</p>
              <p className={styles.Username}>@sarah_chen</p>
            </div>
            <p className={styles.Bio}>Design Engineer at Acme Inc. Building beautiful interfaces and design systems.</p>
            <div className={styles.Stats}>
              <div className={styles.Stat}>
                <span className={styles.StatValue}>2,456</span>
                <span className={styles.StatLabel}>Following</span>
              </div>
              <div className={styles.Stat}>
                <span className={styles.StatValue}>14.5K</span>
                <span className={styles.StatLabel}>Followers</span>
              </div>
            </div>
          </div>
        </HoverCard.Content>
      </HoverCard.Positioner>
    </Portal>
  </HoverCard.Root>
)
```

### Controlled

The controlled `HoverCard` component provides an interface for managing the state of the hover card using the `open` and
`onOpenChange` props:

```tsx
import { HoverCard } from '@ark-ui/react/hover-card'
import { Portal } from '@ark-ui/react/portal'
import { useState } from 'react'
import button from 'styles/button.module.css'
import styles from 'styles/hover-card.module.css'

export const Controlled = () => {
  const [open, setOpen] = useState(false)

  return (
    <div className="stack">
      <button type="button" className={button.Root} onClick={() => setOpen(!open)}>
        Toggle
      </button>
      <HoverCard.Root open={open} onOpenChange={(e) => setOpen(e.open)}>
        <p>
          Liked by{' '}
          <HoverCard.Trigger className={styles.Trigger} asChild>
            <a href="#profile">@sarah_chen</a>
          </HoverCard.Trigger>{' '}
          and 3 others
        </p>
        <Portal>
          <HoverCard.Positioner>
            <HoverCard.Content className={styles.Content}>
              <HoverCard.Arrow className={styles.Arrow}>
                <HoverCard.ArrowTip className={styles.ArrowTip} />
              </HoverCard.Arrow>
              <div className={styles.Body}>
                <img className={styles.Avatar} src="https://i.pravatar.cc/300?u=sarah" alt="Sarah Chen" />
                <div>
                  <p className={styles.Name}>Sarah Chen</p>
                  <p className={styles.Username}>@sarah_chen</p>
                </div>
                <p className={styles.Bio}>Design Engineer at Acme Inc.</p>
              </div>
            </HoverCard.Content>
          </HoverCard.Positioner>
        </Portal>
      </HoverCard.Root>
    </div>
  )
}
```

### Root Provider

An alternative way to control the hover card is to use the `RootProvider` component and the `useHoverCard` hook. This
way you can access the state and methods from outside the component.

```tsx
import { HoverCard, useHoverCard } from '@ark-ui/react/hover-card'
import { Portal } from '@ark-ui/react/portal'
import styles from 'styles/hover-card.module.css'

export const RootProvider = () => {
  const hoverCard = useHoverCard()

  return (
    <div className="stack">
      <output>Open: {String(hoverCard.open)}</output>
      <HoverCard.RootProvider value={hoverCard}>
        <p>
          Liked by{' '}
          <HoverCard.Trigger className={styles.Trigger} asChild>
            <a href="#profile">@sarah_chen</a>
          </HoverCard.Trigger>{' '}
          and 3 others
        </p>
        <Portal>
          <HoverCard.Positioner>
            <HoverCard.Content className={styles.Content}>
              <HoverCard.Arrow className={styles.Arrow}>
                <HoverCard.ArrowTip className={styles.ArrowTip} />
              </HoverCard.Arrow>
              <div className={styles.Body}>
                <img className={styles.Avatar} src="https://i.pravatar.cc/300?u=sarah" alt="Sarah Chen" />
                <div>
                  <p className={styles.Name}>Sarah Chen</p>
                  <p className={styles.Username}>@sarah_chen</p>
                </div>
                <p className={styles.Bio}>Design Engineer at Acme Inc.</p>
              </div>
            </HoverCard.Content>
          </HoverCard.Positioner>
        </Portal>
      </HoverCard.RootProvider>
    </div>
  )
}
```

### Delay

Control the open and close delay of the hover card using the `openDelay` and `closeDelay` props:

```tsx
import { HoverCard } from '@ark-ui/react/hover-card'
import { Portal } from '@ark-ui/react/portal'
import styles from 'styles/hover-card.module.css'

export const Delay = () => (
  <HoverCard.Root openDelay={200} closeDelay={500}>
    <p>
      Liked by{' '}
      <HoverCard.Trigger className={styles.Trigger} asChild>
        <a href="#profile">@sarah_chen</a>
      </HoverCard.Trigger>{' '}
      and 3 others
    </p>
    <Portal>
      <HoverCard.Positioner>
        <HoverCard.Content className={styles.Content}>
          <HoverCard.Arrow className={styles.Arrow}>
            <HoverCard.ArrowTip className={styles.ArrowTip} />
          </HoverCard.Arrow>
          <div className={styles.Body}>
            <img className={styles.Avatar} src="https://i.pravatar.cc/300?u=sarah" alt="Sarah Chen" />
            <div>
              <p className={styles.Name}>Sarah Chen</p>
              <p className={styles.Username}>@sarah_chen</p>
            </div>
            <p className={styles.Bio}>Design Engineer at Acme Inc.</p>
          </div>
        </HoverCard.Content>
      </HoverCard.Positioner>
    </Portal>
  </HoverCard.Root>
)
```

### Positioning

The `HoverCard` component can be customized in its placement and distance from the trigger element through the
`positioning` prop:

```tsx
import { HoverCard } from '@ark-ui/react/hover-card'
import { Portal } from '@ark-ui/react/portal'
import styles from 'styles/hover-card.module.css'

export const Positioning = () => (
  <HoverCard.Root positioning={{ placement: 'right', gutter: 12 }}>
    <p>
      Liked by{' '}
      <HoverCard.Trigger className={styles.Trigger} asChild>
        <a href="#profile">@sarah_chen</a>
      </HoverCard.Trigger>{' '}
      and 3 others
    </p>
    <Portal>
      <HoverCard.Positioner>
        <HoverCard.Content className={styles.Content}>
          <HoverCard.Arrow className={styles.Arrow}>
            <HoverCard.ArrowTip className={styles.ArrowTip} />
          </HoverCard.Arrow>
          <div className={styles.Body}>
            <img className={styles.Avatar} src="https://i.pravatar.cc/300?u=sarah" alt="Sarah Chen" />
            <div>
              <p className={styles.Name}>Sarah Chen</p>
              <p className={styles.Username}>@sarah_chen</p>
            </div>
            <p className={styles.Bio}>Design Engineer at Acme Inc.</p>
          </div>
        </HoverCard.Content>
      </HoverCard.Positioner>
    </Portal>
  </HoverCard.Root>
)
```

### Context

Access the hover card's state with `HoverCard.Context` or the `useHoverCardContext` hook:

```tsx
import { HoverCard } from '@ark-ui/react/hover-card'
import { Portal } from '@ark-ui/react/portal'
import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react'
import styles from 'styles/hover-card.module.css'

export const Context = () => (
  <HoverCard.Root>
    <HoverCard.Context>
      {(context) => (
        <p>
          Liked by{' '}
          <HoverCard.Trigger className={styles.Trigger} asChild>
            <a href="#profile">@sarah_chen {context.open ? <ChevronUpIcon /> : <ChevronDownIcon />}</a>
          </HoverCard.Trigger>{' '}
          and 3 others
        </p>
      )}
    </HoverCard.Context>
    <Portal>
      <HoverCard.Positioner>
        <HoverCard.Content className={styles.Content}>
          <HoverCard.Arrow className={styles.Arrow}>
            <HoverCard.ArrowTip className={styles.ArrowTip} />
          </HoverCard.Arrow>
          <div className={styles.Body}>
            <img className={styles.Avatar} src="https://i.pravatar.cc/300?u=sarah" alt="Sarah Chen" />
            <div>
              <p className={styles.Name}>Sarah Chen</p>
              <p className={styles.Username}>@sarah_chen</p>
            </div>
            <p className={styles.Bio}>Design Engineer at Acme Inc.</p>
          </div>
        </HoverCard.Content>
      </HoverCard.Positioner>
    </Portal>
  </HoverCard.Root>
)
```

### Multiple Triggers

Share a single hover card across multiple trigger elements. Pass a `value` to each `HoverCard.Trigger` — the card
repositions to the active trigger without closing.

```tsx
import { HoverCard } from '@ark-ui/react/hover-card'
import { Portal } from '@ark-ui/react/portal'
import { useState } from 'react'
import styles from 'styles/hover-card.module.css'

interface Profile {
  id: string
  name: string
  username: string
  avatar: string
  bio: string
}

const profiles: Profile[] = [
  {
    id: 'sarah',
    name: 'Sarah Chen',
    username: '@sarah_chen',
    avatar: 'https://i.pravatar.cc/300?u=sarah',
    bio: 'Design Engineer at Acme Inc. Building beautiful interfaces.',
  },
  {
    id: 'alex',
    name: 'Alex Rivera',
    username: '@alex_r',
    avatar: 'https://i.pravatar.cc/300?u=alex',
    bio: 'Full-stack developer and open source contributor.',
  },
  {
    id: 'jordan',
    name: 'Jordan Lee',
    username: '@jordan_lee',
    avatar: 'https://i.pravatar.cc/300?u=jordan',
    bio: 'DevOps lead. Automating all the things.',
  },
]

export const MultipleTriggers = () => {
  const [activeProfile, setActiveProfile] = useState<Profile | null>(null)

  return (
    <HoverCard.Root
      onTriggerValueChange={(e) => {
        setActiveProfile(profiles.find((p) => p.id === e.value) ?? null)
      }}
    >
      <p className={styles.Paragraph}>
        Reviewed by{' '}
        <HoverCard.Trigger value="sarah" asChild>
          <a href="#" className={styles.Trigger}>
            @sarah_chen
          </a>
        </HoverCard.Trigger>
        ,{' '}
        <HoverCard.Trigger value="alex" asChild>
          <a href="#" className={styles.Trigger}>
            @alex_r
          </a>
        </HoverCard.Trigger>
        , and{' '}
        <HoverCard.Trigger value="jordan" asChild>
          <a href="#" className={styles.Trigger}>
            @jordan_lee
          </a>
        </HoverCard.Trigger>
      </p>
      <Portal>
        <HoverCard.Positioner>
          <HoverCard.Content className={styles.Content}>
            <HoverCard.Arrow className={styles.Arrow}>
              <HoverCard.ArrowTip className={styles.ArrowTip} />
            </HoverCard.Arrow>
            {activeProfile && (
              <div className={styles.Body}>
                <div className={styles.Header}>
                  <img className={styles.Avatar} src={activeProfile.avatar} alt={activeProfile.name} />
                </div>
                <div>
                  <p className={styles.Name}>{activeProfile.name}</p>
                  <p className={styles.Username}>{activeProfile.username}</p>
                </div>
                <p className={styles.Bio}>{activeProfile.bio}</p>
              </div>
            )}
          </HoverCard.Content>
        </HoverCard.Positioner>
      </Portal>
    </HoverCard.Root>
  )
}
```

## API Reference

### Props

### Root

#### Props

**`closeDelay`**
Type: `number`
Required: false
Default Value: `300`
Description: The duration from when the mouse leaves the trigger or content until the hover card closes.

**`defaultOpen`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: The initial open state of the hover card when rendered.
Use when you don't need to control the open state of the hover card.

**`defaultTriggerValue`**
Type: `string`
Required: false
Default Value: `undefined`
Description: The initial trigger value when rendered.
Use when you don't need to control the trigger value.

**`disabled`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Whether the hover card is disabled

**`hideMode`**
Type: `HideMode`
Required: false
Default Value: `'display-none'`
Description: How to hide content when mounted but not present.
- `'display-none'`: HTML `hidden` attribute. Effects stay alive.
- `'activity'`: React 19 `<Activity mode="hidden">`. Effects pause. Requires React 19+.

**`id`**
Type: `string`
Required: false
Default Value: `undefined`
Description: The unique identifier of the machine.

**`ids`**
Type: `Partial<{
  trigger: string | ((value?: string | undefined) => string)
  content: string
  positioner: string
  arrow: string
}>`
Required: false
Default Value: `undefined`
Description: The ids of the elements in the popover. Useful for composition.

**`immediate`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Whether to synchronize the present change immediately or defer it to the next frame

**`lazyMount`**
Type: `boolean`
Required: false
Default Value: `false`
Description: Whether to enable lazy mounting

**`onExitComplete`**
Type: `VoidFunction`
Required: false
Default Value: `undefined`
Description: Function called when the animation ends in the closed state

**`onFocusOutside`**
Type: `(event: FocusOutsideEvent) => void`
Required: false
Default Value: `undefined`
Description: Function called when the focus is moved outside the component

**`onInteractOutside`**
Type: `(event: InteractOutsideEvent) => void`
Required: false
Default Value: `undefined`
Description: Function called when an interaction happens outside the component

**`onOpenChange`**
Type: `(details: OpenChangeDetails) => void`
Required: false
Default Value: `undefined`
Description: Function called when the hover card opens or closes.

**`onPointerDownOutside`**
Type: `(event: PointerDownOutsideEvent) => void`
Required: false
Default Value: `undefined`
Description: Function called when the pointer is pressed down outside the component

**`onTriggerValueChange`**
Type: `(details: TriggerValueChangeDetails) => void`
Required: false
Default Value: `undefined`
Description: Function called when the trigger value changes.

**`open`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: The controlled open state of the hover card

**`openDelay`**
Type: `number`
Required: false
Default Value: `600`
Description: The duration from when the mouse enters the trigger until the hover card opens.

**`positioning`**
Type: `PositioningOptions`
Required: false
Default Value: `undefined`
Description: The user provided options used to position the popover content

**`present`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Whether the node is present (controlled by the user)

**`skipAnimationOnMount`**
Type: `boolean`
Required: false
Default Value: `false`
Description: Whether to allow the initial presence animation.

**`triggerValue`**
Type: `string`
Required: false
Default Value: `undefined`
Description: The controlled trigger value

**`unmountOnExit`**
Type: `boolean`
Required: false
Default Value: `false`
Description: Whether to unmount on exit.

### Arrow

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

### ArrowTip

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

### Content

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

#### Data Attributes

**`data-scope`**: hover-card
**`data-part`**: content
**`data-state`**: "open" | "closed"
**`data-nested`**: popover
**`data-has-nested`**: popover
**`data-placement`**: The placement of the content
**`data-side`**: The side of the trigger that the content is positioned on

### Positioner

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

### RootProvider

#### Props

**`value`**
Type: `UseHoverCardReturn`
Required: true
Default Value: `undefined`
Description: undefined

**`hideMode`**
Type: `HideMode`
Required: false
Default Value: `'display-none'`
Description: How to hide content when mounted but not present.
- `'display-none'`: HTML `hidden` attribute. Effects stay alive.
- `'activity'`: React 19 `<Activity mode="hidden">`. Effects pause. Requires React 19+.

**`immediate`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Whether to synchronize the present change immediately or defer it to the next frame

**`lazyMount`**
Type: `boolean`
Required: false
Default Value: `false`
Description: Whether to enable lazy mounting

**`onExitComplete`**
Type: `VoidFunction`
Required: false
Default Value: `undefined`
Description: Function called when the animation ends in the closed state

**`present`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Whether the node is present (controlled by the user)

**`skipAnimationOnMount`**
Type: `boolean`
Required: false
Default Value: `false`
Description: Whether to allow the initial presence animation.

**`unmountOnExit`**
Type: `boolean`
Required: false
Default Value: `false`
Description: Whether to unmount on exit.

### Trigger

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

**`value`**
Type: `string`
Required: false
Default Value: `undefined`
Description: The value that identifies this specific trigger

#### Data Attributes

**`data-scope`**: hover-card
**`data-part`**: trigger
**`data-placement`**: The placement of the trigger
**`data-side`**: The side of the trigger that the trigger is positioned on
**`data-value`**: The value of the item
**`data-current`**: Present when current
**`data-state`**: "open" | "closed"

### Context

**API:**

| Property | Type | Description |
|----------|------|-------------|
| `open` | `boolean` | Whether the hover card is open |
| `setOpen` | `(open: boolean) => void` | Function to open the hover card |
| `triggerValue` | `string | null` | The trigger value |
| `setTriggerValue` | `(value: string | null) => void` | Function to set the trigger value |
| `reposition` | `(options?: Partial<PositioningOptions>) => void` | Function to reposition the popover |
