HoverCard

A card of supplementary details that opens beside a link, like a link preview.

StableSince 1.0.0
On this page

Import

import { HoverCard } from '@envsemble/envui';

Usage

A HoverCard opens its details, children, beside its trigger, which receives the ref.

  • It opens on hover after delay, 600 ms by default, and at once on keyboard focus.
  • It closes closeDelay, 300 ms, after the pointer leaves the trigger and the card.
  • Leave it uncontrolled, or control it with open and onOpenChange; defaultOpen opens it on the first render.
DocumentPreview.tsx
import { HoverCard, Link, Column, Text } from '@envsemble/envui';

export default function DocumentPreview() {
  return (
    <Text>
      The launch depends on the pricing review and the{' '}
      <HoverCard
        // Shown open in the docs; without defaultOpen, it opens on hover and focus.
        defaultOpen
        trigger={<Link href="/documents/roadmap">roadmap</Link>}
      >
        <Column gap={2}>
          <Text render={<strong />} variant="title">
            Roadmap
          </Text>
          <Text emphasis="muted">Changed today by Alex Morgan. 3 open decisions, 1 blocked.</Text>
        </Column>
      </HoverCard>
      .
    </Text>
  );
}

Text triggers

A trigger that is text rather than a link, such as a span or Text that holds text, takes a quiet dotted underline, env-hover-detail. Make it focusable with tabIndex={0}, so keyboard focus opens the card too; envUI warns in the console while developing when it isn't. A link or another control keeps its own look.

<HoverCard trigger={<span tabIndex={0}>28 h 9 min</span>}>
  <Text emphasis="muted">Reviews 11 h 40 min, drafting 9 h 5 min, meetings 7 h 24 min.</Text>
</HoverCard>

Width and placement

width sets how wide the card grows with its content: md, the default, from 12 rem up to 20 rem, or lg, from 20 rem up to 28 rem. It narrows to fit the window. side is bottom, the default, top, left, right, or inline-start and inline-end, which follow the text direction; align is center, the default, start or end.

<HoverCard
  side="top"
  align="start"
  trigger={<Link href="/plans/sync-conflicts">sync conflicts</Link>}
>
  …
</HoverCard>

Composition

Put a heading in it as Text in the title type, and keep links, buttons and fields out of it. A Tooltip around a HoverCard, or as its trigger, shows no tooltip.

Customize

The card, env-hover-card, renders on PopupSurface in its trigger's theme and text direction, above dialogs, and takes className, style, ref and data attributes.

Its popup is frosted, as every popup is: --env-popup-opacity, --env-popup-blur and --env-popup-shadow, set on a theme, change it, as Popover describes.

Accessibility

You provide

  • A trigger that works on its own, such as a link to a page with the same details.
  • tabIndex={0} on a text trigger, so keyboard focus reaches it.
  • Headings and emphasis inside the card, such as Text in the title type.

envUI provides

  • A card that opens on keyboard focus as on hover, and closes with Esc.
  • Focus that stays on the trigger: the card never takes it and isn't a dialog.
  • The theme of its trigger, above dialogs.

Props

HoverCard

Supplementary details that open beside their trigger on hover and keyboard focus, like a link preview. className, style, ref and data attributes go to the card.

PropTypeDescription
triggerrequired
ReactElement
The element that opens the card on hover and keyboard focus; it receives the ref. Text, such as a span or Text that holds text, takes a quiet dotted underline, env-hover-detail; give it tabIndex={0}, so keyboard focus reaches it, which envUI reports while developing. A link or another control keeps its own look.
childrenrequired
ReactNode
The details. Supplementary: never the only place essential information appears.
sideDefault 'bottom'
'top''bottom''left''right''inline-start''inline-end'
bottom, top, left or right, or inline-start and inline-end, which follow the text direction.
alignDefault 'center'
'start''center''end'
Lines the card up with the trigger's center, start or end along the side.
delayDefault 600
number
Milliseconds the pointer rests on the trigger before the card opens; focus opens it at once.
closeDelayDefault 300
number
Milliseconds before it closes once the pointer leaves the trigger and the card.
widthDefault 'md'
'md''lg'
The widest the card grows: md, 20 rem, or lg, 28 rem. It is as wide as its content from 12 rem up, and narrows to fit the window.
open
boolean
Whether the card shows; with `onOpenChange` it controls the card.
defaultOpenDefault false
boolean
Whether an uncontrolled card starts open.
onOpenChange
(open: boolean, details: HoverCardOpenChangeDetails) => void
Called with the new state, and why, when hover, focus or Esc opens or closes the card.
skeletonDefault false
boolean
Shows it and its content as a busy skeleton while that loads; turning it on or off renders the content anew.

Also accepts the native props of <div>, such as ref, className and aria-* attributes.

Part names

Each part's class and state attributes are public and versioned, for an application's CSS to style.

env-hover-card
The card that opens on hover.
data-width
lg

Changelog

1.0.0

A text trigger, such as a span or Text that holds text, takes a quiet dotted underline, env-hover-detail, and one without tabIndex gets a warning while developing. width is md or lg, the widest the card grows as it sizes to its content; className, style, ref and data attributes reach the card, env-hover-card, which renders on PopupSurface in the trigger's text direction. A Tooltip around it, or as its trigger, shows no tooltip.

1.0.0-prerelease.6

A hover card opens over --env-motion-duration-medium, fading in and growing from 98 % with --env-motion-ease-enter, rather than growing from 96 % over the slow duration, so it shows from its first frames rather than late.

A hover card's corners are the popups' own, as a popover's are, rather than a surface's.

1.0.0-prerelease.5

Hover cards are frosted: the popup's color lets a little of what is behind through, blurred, with a soft shadow and no outline edge but a faint hairline in dark, and is solid with its edge at high contrast and with reduced transparency. Its inset is a panel's, as wide as a popup row's corner: 14 px, 11.2 px at the compact scale.