Tessina UI
Tessina UI
GitHubIntroduction
InstallationUsageTheming
Components
ButtonIconButtonLinkSpinnerBadgeAvatarStatusChipShortcutSkeletonSurfaceProgressMeterRating
LabelFieldFieldsetCheckboxRadioSwitchSliderSelectComboboxSearchTextareaNumberFieldDate PickerTime PickerOTP InputFile UploadCalendar
AlertBannerToastTooltip
TabsAccordionCollapsibleBreadcrumbPaginationStepperSegmentedControlButtonGroupToggleButtonToggleGroupToolbarNavigation MenuMenubarBottom NavSidebar
Split ButtonFABDropdown MenuContextMenuCommandPopoverHoverCard
ContainerStackFlexGridAspectRatioSpacerCardCarouselDividerScroll Area
Table
ChatBubblePromptInputCodeBlock
ModalAlertDialogDrawerAction SheetTop Header MobileTop Header DesktopEmptyStateForm
Contributing
ComponentsAction Blocks

HoverCard

A floating card that appears when a trigger is hovered or focused. Use for lightweight previews — user profiles, link previews, citations, or footnote definitions. Built on Base UI's preview-card primitive.

Playground

Installation

pnpm add @tessinaui/ui

Usage

import {
  HoverCard,
  HoverCardTrigger,
  HoverCardContent,
  HoverCardHeader,
  HoverCardTitle,
  HoverCardDescription,
  HoverCardBody,
  HoverCardFooter,
  HoverCardArrow,
} from "@tessinaui/ui";
<HoverCard>
  <HoverCardTrigger render={<button>@blaz</button>} />
  <HoverCardContent side="bottom" align="start">
    <HoverCardHeader leading={<Avatar initials="BZ" />}>
      <HoverCardTitle>Blaz Zorcic</HoverCardTitle>
      <HoverCardDescription>Designer · Building TessinaUI.</HoverCardDescription>
    </HoverCardHeader>
    <HoverCardFooter>
      <Button variant="outline" size="xs">Message</Button>
      <Button size="xs">Follow</Button>
    </HoverCardFooter>
    <HoverCardArrow />
  </HoverCardContent>
</HoverCard>

Showcase

When to use HoverCard vs. Tooltip vs. Popover

Use HoverCard when…Use Tooltip when…Use Popover when…
The preview is rich (avatar, description, actions)You only need short informational textThe user needs interactive controls (forms, lists)
Trigger is hover/focus (mouse + keyboard)Trigger is hover/focus and content is non-interactiveTrigger is click
Touch users gracefully don't see the previewTouch users gracefully don't see the tipWorks equally on touch + mouse
Examples: user profile, link preview, citationExamples: button label, icon meaningExamples: filter dropdown, rename input

Touch behaviour. HoverCard is mouse/keyboard-only. On touch devices Base UI swallows the hover gesture so the trigger just behaves like a normal button. If you need an equivalent on touch, pair it with a Popover triggered by click, or surface the same content elsewhere.

Anatomy

Only HoverCard, HoverCardTrigger, and HoverCardContent are required. Everything else composes optionally inside HoverCardContent.

<HoverCard>
  <HoverCardTrigger>…</HoverCardTrigger>
  <HoverCardContent>
    <HoverCardHeader>
      <HoverCardTitle />
      <HoverCardDescription />
    </HoverCardHeader>
    <HoverCardBody />
    <HoverCardFooter />
    <HoverCardArrow />
  </HoverCardContent>
</HoverCard>

Size

SizeWidthText
"sm"w-64 (16rem)xs
"md" (default)w-72 (18rem)sm
"lg"w-80 (20rem)sm
"xl"w-96 (24rem)base

Intent

intent drives the optional border colour (when showIntentBorder is on) and the arrow's stroke. The popup keeps a neutral border by default — opt in with showIntentBorder for status previews.

ValueBorder with showIntentBorder
"none" (default)border-border
"error"border-error
"warning"border-warning
"success"border-success
"info"border-info

Rounded

ValueCSS
"none"rounded-none
"sm"rounded-md
"md" (default)rounded-lg
"lg"rounded-xl
"full"rounded-3xl

Positioning

HoverCardContent accepts side (top | right | bottom | left), align (start | center | end), sideOffset (px gap from trigger, default 8), and alignOffset (px shift along the side, default 0).

<HoverCardContent side="right" align="start" sideOffset={12}>
  …
</HoverCardContent>

Delays

Pass delay (open) and closeDelay (close) on the root, in milliseconds. Defaults match Base UI: delay = 600, closeDelay = 300.

<HoverCard delay={300} closeDelay={150}>
  …
</HoverCard>

The values propagate to HoverCardTrigger via context — override per-trigger if you have multiple triggers in one card group.

Header slots

HoverCardHeader takes optional leading (avatar / icon) and trailing (badge / status) slots in addition to its title + description children.

<HoverCardHeader
  leading={<Avatar initials="BZ" />}
  trailing={<Badge variant="dot" color="success" />}
>
  <HoverCardTitle>Blaz Zorcic</HoverCardTitle>
  <HoverCardDescription>Online now</HoverCardDescription>
</HoverCardHeader>

Matching button corners to the card

HoverCardFooter is a generic slot — buttons inside don't auto-inherit the card's rounded. Pass rounded explicitly on each button to keep its corners flowing into the card edge:

<HoverCard rounded="none">
  <HoverCardTrigger render={<button>@blaz</button>} />
  <HoverCardContent>
    …
    <HoverCardFooter>
      {/* match the HoverCard's rounded prop */}
      <Button variant="outline" size="xs" rounded="none">Message</Button>
      <Button variant="primary" size="xs" rounded="none">Follow</Button>
    </HoverCardFooter>
  </HoverCardContent>
</HoverCard>

Controlled

HoverCard accepts open, defaultOpen, and onOpenChange.

const [open, setOpen] = React.useState(false);

<HoverCard open={open} onOpenChange={setOpen}>
  …
</HoverCard>

Accessibility

  • Built on @base-ui/react/preview-card — opens on hover or keyboard focus of the trigger.
  • The card's content is announced when focus moves into it; otherwise it remains presentational while the trigger is hovered.
  • Pressing Escape closes the card.
  • On touch input the card does not open — the trigger is announced as a normal button.
  • Use intent="error" or "warning" with showIntentBorder to give status previews a visual signal that complements text content.

RTL

Pass dir="rtl" to the root. Header alignment, the leading/trailing slots, and footer button order all flip to follow the reading direction.

<HoverCard dir="rtl">
  <HoverCardTrigger render={<button>@blaz</button>} />
  <HoverCardContent>
    <HoverCardHeader>
      <HoverCardTitle>بلاز زورتشيتش</HoverCardTitle>
      <HoverCardDescription>مصمم · يبني TessinaUI.</HoverCardDescription>
    </HoverCardHeader>
    <HoverCardArrow />
  </HoverCardContent>
</HoverCard>

API Reference

HoverCard (root)

PropTypeDefaultDescription
size"sm" | "md" | "lg" | "xl""md"Width + text size of the popup
rounded"none" | "sm" | "md" | "lg" | "full""md"Corner radius
intent"none" | "error" | "warning" | "success" | "info""none"Used by the optional intent border
showIntentBorderbooleanfalseWhen true, the popup border picks up the intent colour
dir"ltr" | "rtl""ltr"Reading direction
delaynumber600 (Base UI)Open delay in ms (forwarded to Trigger)
closeDelaynumber300 (Base UI)Close delay in ms (forwarded to Trigger)
openboolean—Controlled open state
defaultOpenbooleanfalseUncontrolled initial state
onOpenChange(open, event) => void—Fired when open state changes

HoverCardContent

PropTypeDefaultDescription
side"top" | "right" | "bottom" | "left""bottom"Which side of the trigger to position on
align"start" | "center" | "end""center"Alignment along the side axis
sideOffsetnumber8Distance in px from the trigger
alignOffsetnumber0Shift along the side axis
portalbooleantrueRender inside a portal
containerHTMLElement | nulldocument.bodyPortal target
size, rounded, intent, showIntentBorder—inheritedOverride the root's variant

HoverCardHeader

PropTypeDefaultDescription
leadingReactNode—Avatar or icon rendered beside the title
trailingReactNode—Slot for badge, status dot, or follow button

HoverCardTrigger

Renders a <button>. Use render={<a href="…" />} to swap in a link, or render={<MyComponent />} for any element. Accepts delay / closeDelay to override the values inherited from the root.

Sub-components

HoverCardTitle, HoverCardDescription, HoverCardBody, HoverCardFooter, HoverCardArrow, HoverCardBackdrop — all accept className and any HTML props.

Notes

  • Built on @base-ui/react/preview-card — Base UI's name for the same primitive Radix and shadcn call HoverCard.
  • Enter/exit animations use Base UI's data-[starting-style] / data-[ending-style] plus position-aware data-[side=*] attributes, so the popup "lifts off" from whichever side it opens on.
  • The arrow is drawn as a single rotated square — no SVG — so it inherits the surface colour and (when showIntentBorder is on) the intent border colour automatically.

Popover

A floating panel that appears next to its trigger and holds interactive content. Click-activated, with full keyboard support, positioning, an optional arrow, and compound parts for header, body, and footer.

Container

A layout primitive that constrains content to a maximum width, applies consistent horizontal padding, and centers it within the viewport. Seven sizes, seven padding presets, polymorphic rendering, and RTL support.

On this page

PlaygroundInstallationUsageShowcaseWhen to use HoverCard vs. Tooltip vs. PopoverAnatomySizeIntentRoundedPositioningDelaysHeader slotsMatching button corners to the cardControlledAccessibilityRTLAPI ReferenceHoverCard (root)HoverCardContentHoverCardHeaderHoverCardTriggerSub-componentsNotes