Preview Card
v0.0.10
mix mishka.ui.gen.headless preview_card
Overview of the Phoenix and LiveView Headless Preview Card Component
The Mishka Chelekom Headless Preview Card ships zero opinionated styling - only the semantic markup, anchored popup positioning (side, align, offset, edge-flip and viewport clamp), and paired-presence state (data-open/data-closed). Every part - trigger, popup, and arrow - is addressable through a *_class attribute, so you style it entirely with your own Tailwind classes while the anchoring and behavior keep working underneath. It is non-modal and never steals focus from the page.
Base UI Preview Card example (Phoenix headless)
Typography is the art and science of arranging type to make written language clear, visually appealing, and effective in communication.
<p class="m-0 text-base text-neutral-950 text-balance dark:text-white">
The principles of good
<.preview_card
id="baseui-preview_card-hero"
side_offset={8}
class="inline"
trigger_class="cursor-pointer text-neutral-950 underline decoration-neutral-950/60 decoration-1 underline-offset-2 outline-0 hover:decoration-neutral-950 data-[popup-open]:decoration-neutral-950 focus-visible:no-underline focus-visible:outline-2 focus-visible:outline-neutral-950 dark:text-white dark:decoration-white/60 dark:hover:decoration-white dark:data-[popup-open]:decoration-white dark:focus-visible:outline-white"
popup_class="group relative h-[var(--popup-height,auto)] w-[var(--popup-width,auto)] origin-[var(--transform-origin)] border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 transition-[transform,opacity] duration-100 ease-out data-[ending-style]:[transform:scale(0.98)] data-[ending-style]:opacity-0 data-[starting-style]:[transform:scale(0.98)] data-[starting-style]:opacity-0 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none"
arrow_class="relative block h-1.5 w-3 overflow-clip group-data-[side=bottom]:top-[-6px] group-data-[side=left]:right-[-9px] group-data-[side=left]:rotate-90 group-data-[side=right]:left-[-9px] group-data-[side=right]:-rotate-90 group-data-[side=top]:bottom-[-6px] group-data-[side=top]:rotate-180 before:absolute before:bottom-0 before:left-1/2 before:h-[calc(6px*sqrt(2))] before:w-[calc(6px*sqrt(2))] before:border before:border-neutral-950 before:bg-white before:content-[''] before:[transform:translate(-50%,50%)_rotate(45deg)] dark:before:border-white dark:before:bg-neutral-950"
>
<:trigger>typography</:trigger>
<:arrow></:arrow>
<div class="flex w-min flex-col gap-2 p-2">
<img
width="224"
height="150"
class="block max-w-none"
src="https://images.unsplash.com/photo-1619615391095-dfa29e1672ef?q=80&w=448&h=300"
alt="Station Hofplein signage in Rotterdam, Netherlands"
/>
<p class="m-0 text-sm text-pretty">
<strong>Typography</strong> is the art and science of arranging type to make written
language clear, visually appealing, and effective in communication.
</p>
</div>
</.preview_card>
remain in the digital age.
</p>Parts & data attributes
Each part carries a stable data-part and a structural chelekom-preview_card__* class you can target, plus paired-presence state for open/closed transitions.
| Part | data-part | State / ARIA | Purpose |
|---|---|---|---|
| Root | - | data-open, data-closed, data-side, data-align | The wrapping element that carries the open/closed state. |
| Trigger | trigger | aria-expanded, aria-controls, data-popup-open | The hovered/focused element (usually a link) that reveals the preview. |
| Popup | popup | role="dialog", data-open, data-closed, data-side, data-align, data-starting-style | The floating preview panel, anchored to the trigger. |
| Arrow | arrow | aria-hidden | Optional pointer arrow rendered inside the popup; carries data-side. |
Accessibility
Follows the WAI-ARIA Authoring Practices Guide for a non-modal hover card with anchored positioning: Escape closes the popup, moving the pointer or focus away closes it after close_delay, and moving the pointer into the popup keeps it open. Focus is never stolen - it stays on the trigger, and the popup is reachable by keyboard and hoverable by mouse.
Attributes
| Name | Type | Default | Values | Required | Description |
|---|---|---|---|---|---|
id
|
string
| — | — | Yes | Unique id (anchors aria relationships) |
open
|
boolean
|
false
| — | No | Initial/controlled open state |
side
|
string
|
bottom
|
toprightbottomleft
| No | Preferred side to anchor the popup |
align
|
string
|
center
|
startcenterend
| No | Alignment along the side |
side_offset
|
integer
|
8
| — | No | Gap between trigger and popup (px) |
align_offset
|
integer
|
0
| — | No | Offset along the alignment axis (px) |
delay
|
integer
|
600
| — | No | Hover open delay (ms) |
close_delay
|
integer
|
300
| — | No | Hover/blur close delay (ms) |
close_on_escape
|
boolean
|
true
| — | No | Whether Escape closes |
on_open_change
|
string
| — | — | No | LiveView event pushed on open/close ({open}) |
on_open_change_target
|
string
| — | — | No | Optional pushEventTo target for on_open_change |
class
|
any
| — | — | No | Extra classes for the root |
trigger_class
|
any
| — | — | No | Extra classes for the trigger part |
popup_class
|
any
| — | — | No | Extra classes for the popup part |
arrow_class
|
any
| — | — | No | Extra classes for the arrow part |
rest
|
global
| — | — | No | — |
Slots
| Name | Required | Description |
|---|---|---|
trigger
| Yes | The element that reveals the preview on hover/focus |
arrow
| No | Optional pointer arrow rendered inside the popup (carries data-side) |
inner_block
| Yes | The preview card content |
Options
Each option takes one or more of its values, separated by commas.
| Option | Values |
|---|---|
--type
|
preview_card
|
--module
| A module name of your own |
What it generates
mix mishka.ui.gen.headless preview_card