Skip to content

HoverCard

A card that opens when the pointer rests on something and holds a preview of what is on the other side of it: a person behind a mention, a repository behind a link, a deploy behind an id.

tsx
import { HoverCard, TextLink } from 'neba';

<HoverCard trigger={<TextLink href="/people/nadiarowan">@nadiarowan</TextLink>} title="Nadia Rowan">
  Maintainer · 214 commits
</HoverCard>;

Props

PropTypeDefaultDescription
trigger * ReactElementWhat the card hangs off. One element that accepts a ref and spreads props; the card merges onto it rather than wrapping it
titleReactNodeThe heading
descriptionReactNodeA line under the title
childrenReactNodeThe body
sizeshared'xs' | 'sm' | 'md' | 'lg' | 'xl''md'The type scale, the padding, and how wide the card may get
colorshared'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'Semantic colour role. The sheet is never dyed, so it reaches the edge
densityshared'default' | 'compact''default'Changes the card's inset and nothing else
sideshared'top' | 'right' | 'bottom' | 'left''bottom'Which edge of the trigger it appears on. Flips when there is no room
alignshared'start' | 'center' | 'end''center'Where it sits along that edge
sideOffsetnumber6Distance from the trigger, in pixels
alignOffsetnumber0Shift along that edge, in pixels
arrowbooleanfalseDraws the wedge pointing at the trigger. Off by default: a translucent sheet's wedge cannot carry the blurred backdrop with it
openbooleanWhether the card is open. With onOpenChange it makes it controlled
defaultOpenbooleanWhether it starts open, uncontrolled
onOpenChange(open: boolean) => voidFired whenever it opens or closes
delaynumberHow long the pointer has to rest on the trigger before the card opens, in milliseconds
closeDelaynumberHow long the card stays after the pointer has left, in milliseconds. This is what makes the gap crossable
widthnumber | stringA hard cap on the width, overriding the one size implies. Numbers are pixels

Every native <div> attribute passes through to the popup, apart from color, title and children, which the component owns. There is no variant and no elevation, for the reason Popover has neither: a surface that had to be hovered has already asserted itself, and a card that floats over the page cannot be sat flat.

It sits between the library's other two popups. A Tooltip is a label: one line, and the pointer never reaches it. A Popover was asked for by a press, so it can hold a form. This one is uninvited like a tooltip and reachable like a popover: the pointer can cross into it and a link inside it can be followed.

Examples

trigger

The trigger is an element rather than children, and the card merges onto it: no wrapper, so the layout is unchanged and a link stays a link. Usually a TextLink or an Avatar.

delay · closeDelay

delay is how long the pointer has to rest before the card opens, and closeDelay how long it stays after the pointer leaves: which is what makes the gap between the trigger and the card crossable.

side · align · arrow

side is the edge of the trigger the card appears on, flipping when there is no room; align is where it sits along that edge. arrow draws the wedge, and is off by default because a translucent sheet's wedge cannot carry the blurred backdrop with it.

size

size sets the type scale, the inset and how wide the card is allowed to get. width overrides the last of those on its own.

Accessibility

  • Whatever is in the card must also exist on the page the trigger leads to. A keyboard with no hover, a touchscreen with no pointer, and a screen reader all arrive by that route instead, so this can never be the only way to something.
  • The card is reachable with the pointer, so a link inside it can be followed; it stays open while the pointer is in it.
  • Escape closes it.

Released under the MIT License