Popover <l-popover>
Popovers are used to display rich interactive content in a floating panel anchored to a trigger element. Commonly used for mini forms, additional details, and contextual controls. Dismissed by clicking outside.
<l-popover>Options
Basic
Reference a trigger element by ID using the for attribute. Clicks toggle the popover; clicking outside closes it. The popover does not apply any padding — wrap the slotted content in a container with the spacing you want.
Jane Cooper
Senior Engineer at Acme Corp
Code
<button
id="popover-basic"
class="l-button"
>
View profile
</button>
<l-popover for="popover-basic">
<div class="flex items-center gap-3 px-4 py-3">
<l-avatar
src="https://i.pravatar.cc/150?img=58"
name="Jane Cooper"
></l-avatar>
<div class="flex flex-col gap-0.5">
<p class="font-medium text-primary">Jane Cooper</p>
<p class="text-xs text-secondary">Senior Engineer at Acme Corp</p>
</div>
<button
class="l-button ml-auto"
data-size="sm"
data-variant="primary"
>
Follow
</button>
</div>
</l-popover>Placement
Set placement to control position: bottom (default), top, left, right.
Code
<div class="flex flex-wrap items-center gap-4">
<button
id="popover-top"
class="l-button"
>
Top
</button>
<l-popover
for="popover-top"
placement="top"
>
<span class="block px-4 py-3">Placed on top</span>
</l-popover>
<button
id="popover-bottom"
class="l-button"
>
Bottom
</button>
<l-popover
for="popover-bottom"
placement="bottom"
>
<span class="block px-4 py-3">Placed on bottom</span>
</l-popover>
<button
id="popover-left"
class="l-button"
>
Left
</button>
<l-popover
for="popover-left"
placement="left"
>
<span class="block px-4 py-3">Placed on left</span>
</l-popover>
<button
id="popover-right"
class="l-button"
>
Right
</button>
<l-popover
for="popover-right"
placement="right"
>
<span class="block px-4 py-3">Placed on right</span>
</l-popover>
</div>Without arrow
Add without-arrow to hide the directional arrow.
This popover has no arrow.
Code
<button
id="popover-no-arrow"
class="l-button"
>
Without arrow
</button>
<l-popover
for="popover-no-arrow"
without-arrow
>
<p class="px-4 py-3">This popover has no arrow.</p>
</l-popover>Hover trigger
Set trigger="hover" to open on pointer enter. A safe polygon hover bridge prevents flickering when moving between trigger and popover.
Quick preview
Move your cursor freely between trigger and popover.
Code
<button
id="popover-hover"
class="l-button"
>
Hover me
</button>
<l-popover
for="popover-hover"
trigger="hover"
>
<div class="flex flex-col gap-2 px-4 py-3">
<p class="font-medium">Quick preview</p>
<p class="text-sm text-gray-500">Move your cursor freely between trigger and popover.</p>
</div>
</l-popover>Examples
Safe triangle visualization
Hover the button and move your cursor toward the popover. The safe polygon keeps the popover open while your cursor travels across the gap.
Safe area demo
The red polygon keeps the popover open while your cursor travels between trigger and content.
Mega menu
E-commerce style mega menu: full-width stretches the popover to the viewport, --show-duration: 0ms makes it appear instantly on hover.
Code
<style>
#demo-mega l-popover::part(body) {
border: 0;
border-bottom: 1px solid var(--l-color-divider);
}
</style>
<nav
id="demo-mega"
class="vp-raw -mx-3 -my-6 bg-[var(--vp-c-bg)] border-b border-[var(--l-color-divider)]"
>
<div class="flex items-center px-4">
<button
id="mega-women"
class="cursor-pointer px-5 py-4 text-sm font-medium hover:underline underline-offset-[6px]"
>
Femme
</button>
<button
id="mega-men"
class="cursor-pointer px-5 py-4 text-sm font-medium hover:underline underline-offset-[6px]"
>
Homme
</button>
<button
id="mega-kids"
class="cursor-pointer px-5 py-4 text-sm font-medium hover:underline underline-offset-[6px]"
>
Enfant
</button>
</div>
<l-popover
for="mega-women"
trigger="hover"
placement="bottom-start"
distance="1"
full-width
without-arrow
style="--shadow: none; --border-radius: 0; --show-duration: 0ms; --hide-duration: 0ms"
>
<div class="max-w-5xl mx-auto grid grid-cols-4 gap-8 px-6 py-6">
<div>
<p class="font-medium mb-3">Vêtements</p>
<div class="flex flex-col items-start gap-1.5 text-sm text-gray-600">
<button class="cursor-pointer hover:underline">Nouveautés</button>
<button class="cursor-pointer hover:underline">Robes</button>
<button class="cursor-pointer hover:underline">Tops & T-shirts</button>
<button class="cursor-pointer hover:underline">Mailles</button>
<button class="cursor-pointer hover:underline">Manteaux & vestes</button>
</div>
</div>
<div>
<p class="font-medium mb-3">Chaussures</p>
<div class="flex flex-col items-start gap-1.5 text-sm text-gray-600">
<button class="cursor-pointer hover:underline">Sneakers</button>
<button class="cursor-pointer hover:underline">Bottes</button>
<button class="cursor-pointer hover:underline">Escarpins</button>
<button class="cursor-pointer hover:underline">Ballerines</button>
<button class="cursor-pointer hover:underline">Sandales</button>
</div>
</div>
<div>
<p class="font-medium mb-3">Accessoires</p>
<div class="flex flex-col items-start gap-1.5 text-sm text-gray-600">
<button class="cursor-pointer hover:underline">Sacs</button>
<button class="cursor-pointer hover:underline">Bijoux</button>
<button class="cursor-pointer hover:underline">Ceintures</button>
<button class="cursor-pointer hover:underline">Lunettes</button>
<button class="cursor-pointer hover:underline">Foulards</button>
</div>
</div>
<div class="rounded-lg bg-gray-100 p-4 cursor-pointer hover:bg-gray-200">
<span class="block text-xs uppercase tracking-wide text-gray-500 mb-1">À la une</span>
<span class="block font-medium mb-1">Collection printemps 2026</span>
<span class="block text-sm text-gray-600">Jusqu'à -30 % cette semaine.</span>
</div>
</div>
</l-popover>
<l-popover
for="mega-men"
trigger="hover"
placement="bottom-start"
distance="1"
full-width
without-arrow
style="--shadow: none; --border-radius: 0; --show-duration: 0ms; --hide-duration: 0ms"
>
<div class="max-w-5xl mx-auto grid grid-cols-4 gap-8 px-6 py-6">
<div>
<p class="font-medium mb-3">Vêtements</p>
<div class="flex flex-col items-start gap-1.5 text-sm text-gray-600">
<button class="cursor-pointer hover:underline">Nouveautés</button>
<button class="cursor-pointer hover:underline">Chemises</button>
<button class="cursor-pointer hover:underline">T-shirts & polos</button>
<button class="cursor-pointer hover:underline">Jeans</button>
<button class="cursor-pointer hover:underline">Vestes & manteaux</button>
</div>
</div>
<div>
<p class="font-medium mb-3">Chaussures</p>
<div class="flex flex-col items-start gap-1.5 text-sm text-gray-600">
<button class="cursor-pointer hover:underline">Sneakers</button>
<button class="cursor-pointer hover:underline">Bottes</button>
<button class="cursor-pointer hover:underline">Mocassins</button>
<button class="cursor-pointer hover:underline">Sandales</button>
<button class="cursor-pointer hover:underline">Ville</button>
</div>
</div>
<div>
<p class="font-medium mb-3">Accessoires</p>
<div class="flex flex-col items-start gap-1.5 text-sm text-gray-600">
<button class="cursor-pointer hover:underline">Montres</button>
<button class="cursor-pointer hover:underline">Portefeuilles</button>
<button class="cursor-pointer hover:underline">Ceintures</button>
<button class="cursor-pointer hover:underline">Lunettes</button>
<button class="cursor-pointer hover:underline">Sacs</button>
</div>
</div>
<div class="rounded-lg bg-gray-100 p-4 cursor-pointer hover:bg-gray-200">
<span class="block text-xs uppercase tracking-wide text-gray-500 mb-1">À la une</span>
<span class="block font-medium mb-1">Workwear essentiel</span>
<span class="block text-sm text-gray-600">Les basiques pour la nouvelle saison.</span>
</div>
</div>
</l-popover>
<l-popover
for="mega-kids"
trigger="hover"
placement="bottom-start"
distance="1"
full-width
without-arrow
style="--shadow: none; --border-radius: 0; --show-duration: 0ms; --hide-duration: 0ms"
>
<div class="max-w-5xl mx-auto grid grid-cols-4 gap-8 px-6 py-6">
<div>
<p class="font-medium mb-3">Fille</p>
<div class="flex flex-col items-start gap-1.5 text-sm text-gray-600">
<button class="cursor-pointer hover:underline">Nouveautés</button>
<button class="cursor-pointer hover:underline">Robes</button>
<button class="cursor-pointer hover:underline">Hauts</button>
<button class="cursor-pointer hover:underline">Bas</button>
<button class="cursor-pointer hover:underline">Pyjamas</button>
</div>
</div>
<div>
<p class="font-medium mb-3">Garçon</p>
<div class="flex flex-col items-start gap-1.5 text-sm text-gray-600">
<button class="cursor-pointer hover:underline">Nouveautés</button>
<button class="cursor-pointer hover:underline">T-shirts</button>
<button class="cursor-pointer hover:underline">Pantalons</button>
<button class="cursor-pointer hover:underline">Sweats</button>
<button class="cursor-pointer hover:underline">Pyjamas</button>
</div>
</div>
<div>
<p class="font-medium mb-3">Bébé</p>
<div class="flex flex-col items-start gap-1.5 text-sm text-gray-600">
<button class="cursor-pointer hover:underline">Naissance</button>
<button class="cursor-pointer hover:underline">Bodies</button>
<button class="cursor-pointer hover:underline">Pyjamas</button>
<button class="cursor-pointer hover:underline">Tenues de sortie</button>
<button class="cursor-pointer hover:underline">Accessoires</button>
</div>
</div>
<div class="rounded-lg bg-gray-100 p-4 cursor-pointer hover:bg-gray-200">
<span class="block text-xs uppercase tracking-wide text-gray-500 mb-1">À la une</span>
<span class="block font-medium mb-1">Retour en classe</span>
<span class="block text-sm text-gray-600">Tout pour la rentrée 2026.</span>
</div>
</div>
</l-popover>
</nav>Accessibility
Criteria
- Expanded state
Trigger receives
aria-expandedandaria-controlspointing to the popoverWCAG4.1.2RGAA7.1- Dismissible
Closes on
Escapeand click outside (light-dismiss viapopover="auto")WCAG3.2.2- Hover bridge
Safe polygon prevents flickering when moving cursor from trigger to popover
WCAG1.4.13- Motion
Respects
prefers-reduced-motionWCAG2.3.3
Keyboard interactions
API reference
Importing
import 'luxen-ui/popover';Attributes & Properties
forAttribute- ID of the trigger element
placementAttribute- Preferred placement:
bottom(default),bottom-start,bottom-end,top,top-start,top-end,left,left-start,left-end,right,right-start,right-end distanceAttribute- Offset from trigger in px. Default
8 openAttribute- Whether popover is visible. Reflects to attribute
without-arrowAttribute- Hide the directional arrow
full-widthAttribute- Stretch the popover to the viewport width. Useful for mega menus — typically combined with
without-arrow triggerAttribute- Space-separated trigger modes:
click(default),hover,focus,manual
Methods
show()Method- Shows the popover
hide()Method- Hides the popover
toggle()Method- Toggles the popover
CSS custom properties
--backgroundName- Background color. Default:
Canvas --colorName- Text color. Default: inherited
--border-radiusName- Border radius. Default
8px --max-widthName- Maximum width. Default
320px --shadowName- Box shadow
--arrow-sizeName- Arrow size. Default
8px --show-durationName- Show animation duration. Default
150ms --hide-durationName- Hide animation duration. Default
150ms