Hover Card
A rich popup that appears on hover or focus — designed for previewing content like user profiles, link destinations, or product summaries. Similar to a Tooltip but intended for structured, interactive content.
Basic Usage
Inline in Running Text
Wrap a word or phrase inside running prose with a hover card to surface a glossary entry, contributor profile, or product reference without the reader leaving the sentence. The trigger renders as an inline <button> styled to look like emphasized body text — fully keyboard-focusable, so the card opens on Tab as well as on hover.
The release notes were authored by
The button keeps font: inherit plus vertical-align: baseline; line-height: inherit; so it sits flush with the surrounding inline text — without the explicit baseline + line-height overrides the browser's default <button> baseline drops the trigger a few pixels and bumps the apparent line-height of the run, making the trigger label and the words after it look subtly larger than the words before. The whole sentence is also kept on a single source line so HTML's whitespace collapsing doesn't surface a double-space between the trigger and the next word.
The dotted underline is the conventional cue for a hoverable term in running prose; developers preferring a different affordance (solid underline, accent color) override the inline style attribute.
Pause the cursor over the trigger label for ~300 ms — that's the default delay-show hover-intent buffer — and the profile card animates in below it. Keyboard users can Tab to the button to open it instantly. Lower the buffer with <x-wirekit::hover-card :delay-show="100"> if the example feels sluggish inside a small preview frame.
The panel is teleported out of the document flow via Alpine's x-teleport, into WireKit's overlay landmark near the end of <body>, so the dialog's <div> markup lifts out of the surrounding <p> before the browser parses it — this keeps the running paragraph well-formed and the Alpine $refs.panel lookup intact across the teleport boundary. The landmark is created by WireKit's own JavaScript, so a teleported panel stays inside a region an assistive technology can announce.
Placement
Control where the card appears relative to the trigger:
Available placements: 'top', 'bottom' (default), 'left', 'right', and their -start/-end variants (e.g. 'bottom-start'). The card automatically flips if there isn't enough space, powered by Floating UI.
Custom Delays
Adjust show/hide delays for different use cases:
{{-- Quick preview: short delay --}}
<x-wirekit::hover-card :delay-show="100" :delay-hide="100">
<x-slot:trigger>Quick preview</x-slot:trigger>
Fast-appearing content.
</x-wirekit::hover-card>
{{-- Slow reveal: longer delay --}}
<x-wirekit::hover-card :delay-show="500" :delay-hide="300">
<x-slot:trigger>Slow reveal</x-slot:trigger>
Content that takes longer to appear.
</x-wirekit::hover-card>
Hover Card vs Tooltip
| Feature | Tooltip | Hover Card |
|---|---|---|
| Content | Plain text | Rich HTML (images, buttons, links) |
| Interaction | Read-only | Can contain interactive elements |
| ARIA role | tooltip |
dialog |
| Keyboard | Focus shows, no interaction inside | Focus shows, can Tab into content |
| Use case | Short labels, abbreviations | User profiles, link previews |
Props
| Prop | Type | Default | Description |
|---|---|---|---|
placement |
string | 'bottom' |
Floating UI placement ('top', 'bottom', 'left', 'right', + -start/-end) |
offset |
int | 8 |
Distance from trigger in pixels |
delayShow |
int | 300 |
Milliseconds before showing on hover |
delayHide |
int | 200 |
Milliseconds before hiding on leave |
scope |
string|null | null |
Scoped personalization key |
Slots
| Slot | Purpose |
|---|---|
trigger |
The element that activates the hover card |
| default | Rich content inside the card panel |
Accessibility
- Trigger has
aria-haspopup="dialog"— announces that activation opens a dialog - Trigger has
aria-expanded— toggles between"true"and"false" - Panel uses
role="dialog"— screen readers announce content as dialog - Keyboard: focus on the trigger opens the card,
Tabmoves into its content, andEscapecloses it and returns focus to the trigger - Mouse: hovering trigger or panel keeps card open; moving away starts hide delay
- Card stays open when hovering between trigger and panel (bridge delay prevents flicker)
- SPA-safe: cleans up on Livewire page navigation
Keyboard Interaction
| Key | Action |
|---|---|
Tab (focusing the trigger) |
Open the hover card |
Tab (trigger focused, card holds buttons or links) |
Move into the card, onto its first control |
Tab (trigger focused, card is read-only) |
Move to the next control on the page; the card closes behind you |
Tab (on the card's last control) |
Move to the control that follows the trigger; the card closes |
Shift + Tab (on the card's first control) |
Move back to the trigger; the card closes |
Escape |
Close the card and return focus to the trigger |
The card's panel is rendered at the end of the document so it can position itself freely over the page, which means the browser's own tab order would send you past it rather than into it. The component bridges that: the sequence above is what you get, whatever the panel's position in the markup.
Pitfalls
- Don't put critical info in a hover-card. Hover has no keyboard or touch equivalent — the component reveals on focus too, but discoverability for non-mouse users is poor. For must-read content use
<x-wirekit::popover>with an explicit trigger. - Don't auto-open on page load. Hover-cards are user-triggered.
Design Tokens
| Element | Token |
|---|---|
| Panel background | --color-wk-bg-elevated |
| Panel border | --color-wk-border / --border-wk-width |
| Panel radius | --radius-wk-lg |
| Panel shadow | --shadow-wk-lg |
| Panel padding | --padding-wk-x-md |
| Text color | --color-wk-text |
| Text size | --text-wk-md |
| Font family | --font-wk-sans |
| Transition | --transition-wk-duration |
Customization
Override defaults in config/wirekit.php:
'components' => [
'hover-card' => [],
],