Skip to content
Docs

Hover Card

For sighted users to preview content available behind a link.

For sighted users to preview content available behind a link.

<HoverCard.root
  id="hover-card-primitive"
  open_delay={100}
  close_delay={100}
>
  <HoverCard.trigger
    id="hover-card-trigger"
    content_id="hover-card-content"
  >
    <a
      class="DemoImageTrigger"
      href="https://github.com/"
      target="_blank"
      rel="noreferrer noopener"
    >
      <div
        class="DemoImage normal"
        style="display: flex; align-items: center; justify-content: center; background: var(--gray-3); color: var(--gray-11); font-weight: 600; font-size: 14px;"
        aria-hidden="true"
      >
        E
      </div>
    </a>
  </HoverCard.trigger>
  <HoverCard.portal id="hover-card-portal">
    <HoverCard.content
      id="hover-card-content"
      class="DemoHoverCardContent"
      side_offset={5}
    >
      <div style="display: flex; flex-direction: column; gap: 7px;">
        <div
          class="DemoImage large"
          style="display: flex; align-items: center; justify-content: center; background: var(--gray-3); color: var(--gray-11); font-weight: 600; font-size: 24px;"
          aria-hidden="true"
        >
          E
        </div>
        <div style="display: flex; flex-direction: column; gap: 15px;">
          <div>
            <div class="DemoText bold">Essence</div>
            <div class="DemoText faded">@essence_ui</div>
          </div>
          <div class="DemoText">
            Unstyled, accessible UI components for Phoenix LiveView. Primitives, colors, and themes for building high-quality interfaces.
          </div>
          <div style="display: flex; gap: 15px;">
            <div style="display: flex; gap: 5px;">
              <div class="DemoText bold">0</div>
              <div class="DemoText faded">Following</div>
            </div>
            <div style="display: flex; gap: 5px;">
              <div class="DemoText bold">2,900</div>
              <div class="DemoText faded">Followers</div>
            </div>
          </div>
        </div>
      </div>
      <HoverCard.arrow class="DemoHoverCardArrow" />
    </HoverCard.content>
  </HoverCard.portal>
</HoverCard.root>
Can be controlled or uncontrolled.
Customize side, alignment, offsets, collision handling.
Optionally render a pointing arrow.
Supports custom open and close delays.
Ignored by screen readers.

Anatomy

Import all parts and piece them together.

<HoverCard.root>
  <HoverCard.trigger />
  <HoverCard.portal>
    <HoverCard.content>
      <HoverCard.arrow />
    </HoverCard.content>
  </HoverCard.portal>
</HoverCard.root>

Anatomy

Root
Contains all the parts of a hover card.
Trigger
The link that opens the hover card when hovered. Set `content_id` to the content element's `id` for `aria-describedby`.
Portal
When used, portals the content part into the target (default `body`).
Content
The component that pops out when the hover card is open.
Arrow
An optional arrow element to render alongside the content. Must be rendered inside `HoverCard.content`.

API Reference

Root

Contains all the parts of a hover card.

Use open with on_open_change for controlled open state in LiveView:

<HoverCard.root id="profile-card" open={@open} on_open_change="hover_card_open_change">
  …
</HoverCard.root>
def handle_event("hover_card_open_change", %{"open" => open}, socket) do
  {:noreply, assign(socket, :open, open)}
end
Prop Type Default Description
close_delay integer 150
default_open boolean false
id string
on_open_change string nil
open boolean false
open_delay integer 200
close_delay
Type integer Default 150
default_open
Type boolean Default false
id
Type string Default
on_open_change
Type string Default nil
open
Type boolean Default false
open_delay
Type integer Default 200

Data attributes

Attribute Values Description
[data-state] open | closed Reflects whether the hover card is open.

Trigger

The link that opens the hover card when hovered.

Prop Type Default Description
content_id string nil
id string nil
content_id
Type string Default nil
id
Type string Default nil

Data attributes

Attribute Values Description
[data-state] open | closed Reflects whether the hover card is open.

Portal

When used, portals the content part into the target (default body).

Prop Type Default Description
class any nil
container string "div"
id string
target string "body"
class
Type any Default nil
container
Type string Default "div"
id
Type string Default
target
Type string Default "body"

Content

The component that pops out when the hover card is open.

Prop Type Default Description
align string "center"
id string nil
side string "bottom"
side_offset integer 8
align
Type string Default "center"
id
Type string Default nil
side
Type string Default "bottom"
side_offset
Type integer Default 8

Data attributes

Attribute Values Description
[data-state] open | closed Reflects whether the hover card is open.
[data-side] top | right | bottom | left Preferred side relative to the trigger.
[data-align] start | center | end Alignment along the side.

Arrow

An optional arrow element to render alongside the hover card. This can be used to help visually link the trigger with the content. Must be rendered inside HoverCard.content.

Prop Type Default Description
id string nil
id
Type string Default nil

Examples

Show instantly

Use open_delay and close_delay to control the time it takes for the hover card to open and close.

<HoverCard.root id="instant-hover-card" open_delay={0} close_delay={0}>
  <HoverCard.trigger id="instant-hover-card-trigger" content_id="instant-hover-card-content">
    …
  </HoverCard.trigger>
  <HoverCard.portal id="instant-hover-card-portal">
    <HoverCard.content id="instant-hover-card-content" class="DemoHoverCardContent">
      …
    </HoverCard.content>
  </HoverCard.portal>
</HoverCard.root>

Accessibility

The hover card is intended for sighted users only; the content will be inaccessible to keyboard users.

Keyboard Interactions

Key Description
Tab Opens/closes the hover card.
Enter Opens the hover card link.