Popover
Installation
npx @mielui/svelte add popoveryarn dlx @mielui/svelte add popoverbunx @mielui/svelte add popoverUsage
Bind open on Root when another control needs to open or close the panel. onOpenChange reports changes made inside the component; setting the bound value yourself does not call it. Each Root keeps its own state.
Content has a dialog role, so give it a Title or an aria-label. While a click popover is open, Tab stays inside the panel, the page does not scroll, and content outside it is inert. Set focusTrap and lockScroll to false on Content, and inert={false} on Root, when the rest of the page must stay usable.
Trigger onclick receives the native event before the open state changes. Call preventDefault() to cancel opening or closing.
<script lang="ts">
import * as Popover from '@mielui/svelte/components/popover';
</script>
<Popover.Root>
<Popover.Trigger>Open</Popover.Trigger>
<Popover.Content class="w-64" aria-label="Details">Content here</Popover.Content>
</Popover.Root>Examples
Share form
A form, a member list, and a status line composed inside one panel.
Basic
Placements
placement on Root picks a side and an optional -start or -end alignment. The panel flips when there is no room.
Glass surface
surface="glass" on Content gives the panel a translucent, blurred background. Omit surface to inherit --mielui-surface from the theme, or set surface="solid" to override it. Glass falls back to an opaque fill when backdrop filtering is unavailable or reduced transparency is requested.
Open on hover
hoverable on Root opens the popover when the pointer rests on the trigger, as well as on click. delay is how long the pointer has to rest, in milliseconds, and defaults to 0. closeDelay keeps the panel open after the pointer leaves, 150 ms by default, so people can move onto it. A hover popover does not trap focus, lock scrolling, or make the page inert.
Dismissal and layering
A click popover closes on Escape and on a press outside. allowClickOutside={false} on Content keeps it open until Escape or until you set open to false.
While open, the popover puts an invisible layer over the page so the first outside press only closes it. Set dismissLayer={false} when the trigger has to stay usable while the panel is open, such as a text input that filters the panel. Outside presses still close the popover.
portal moves the panel to the end of the document so a parent with clipped overflow cannot cut it off. Set portal={false} to render it in place, for example inside a container you style with a container query.
refElement anchors the panel to another element or a virtual element in place of the trigger. The panel then opens to the right of that element, which is how submenus use it.
Trigger and state
Trigger is a Button and defaults to the primary variant. icon adds a chevron after the label that turns while the popover is open, and unstyled removes the Button classes. onopen runs just before this trigger opens the popover, which is the place to load the panel's data. Bind element to reach the button.
On Content, class styles the outer frame and surfaceClass styles the inner surface where your children sit.
API reference
Popover.Root
Controls popover state.
childrenSnippet<[]>Content rendered inside.
openBindablebooleanWhether it is open. Bind it to control the state from outside.
Default
falseonOpenChange((open: boolean) => void)Called with the new state whenever it opens or closes.
placementPlacementPreferred side and alignment relative to the trigger, such as
bottom-start. It flips when there is no room.Default
'bottom'hoverablebooleanOpens on hover as well as on click.
delaynumberMilliseconds the pointer rests on the trigger before it opens.
Default
0closeDelaynumberMilliseconds after the pointer leaves before it closes.
Default
150inertbooleanMake document content outside an open non-hover popover inert. Defaults to
true.Default
true
Popover.Content
Renders the popover surface.
surface"solid" | "glass"Surface treatment. Omit it to inherit
--mielui-surfacefrom the theme.childrenRequiredSnippet<[]>Content rendered inside.
class(string & (ClassValue | null))Classes added to the element.
surfaceClassstringClasses for the inset surface (where children live) โ padding, layout, background overrides. The
classprop styles the outer Panel frame.allowClickOutsidebooleanCloses when the pointer is pressed outside it. Set false to keep it open until it is dismissed another way.
Default
truedismissLayerbooleanRender the full-viewport dismiss layer under the panel while open. Defaults to
true. Set tofalsefor triggers that must stay clickable while open (e.g. an input-style combobox trigger); outside pointer dismissal still applies viaallowClickOutside.Default
trueportalbooleanMoves the panel to the end of the document so ancestors cannot clip it. Set false to render it in place.
Default
truerefElementVirtualElementPositions the panel against this element or virtual element instead of the trigger. The panel then opens to the right of it, as a submenu does.
role"dialog" | "alertdialog" | "menu" | "listbox" | "none"ARIA role of the panel.
Default
'dialog'tabindexnumberTab index of the panel.
Default
-1focusTrapbooleanTrap Tab focus inside the panel while open. Defaults to
true.Default
truelockScrollbooleanLock document scrolling while the panel is open. Defaults to
true.Default
true
Popover.Title
Renders the popover title.
classstringClasses added to the element.
childrenSnippet<[]>Content rendered inside.
Popover.Trigger
Opens the popover.
iconbooleanShows the chevron after the label.
Default
falsevariantButtonVariantButton style of the trigger.
size"sm" | "md" | "lg" | "icon"Control height of the trigger.
childrenSnippet<[]>Content rendered inside.
classstringClasses added to the element.
elementBindableHTMLButtonElement | HTMLAnchorElementBindable reference to the DOM element.
unstyledbooleanForwarded to Button: render with
classalone, skipping variant/size.onclick((event: MouseEvent) => void)Called when it is clicked or activated.
onopen(() => void)Called immediately before this trigger opens its popover.
stylestringInline styles for the element.
pnpm dlx @mielui/svelte add popover