Popover
An anchored panel for a small amount of extra control.
More examples
Icon trigger
The default trigger is an icon button named by label.
Source
<script lang="ts">
import 'portal-bits/styles.css';
import 'portal-bits/tokens.css';
import type { Snippet } from 'svelte';
let { children }: { children: Snippet } = $props();
</script>
{@render children()}
<script lang="ts">
import PopoverExample from './PopoverExample.svelte';
</script>
<PopoverExample side={"bottom"} align={"end"} />
<script lang="ts">
import { Popover, Switch } from 'portal-bits';
let {
side = 'bottom',
align = 'end',
}: {
side?: 'top' | 'right' | 'bottom' | 'left';
align?: 'start' | 'center' | 'end';
} = $props();
let notifications = $state(false);
</script>
<Popover
label="Filter settings"
{side}
{align}
triggerClass="p-button p-button--secondary p-button--40"
>
{#snippet trigger()}
<svg
width="15"
height="15"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
><path d="M10 5H3" /><path d="M12 19H3" /><path d="M14 3v4" /><path d="M16 17v4" /><path
d="M21 12h-9"
/><path d="M21 19h-5" /><path d="M21 5h-7" /><path d="M8 10v4" /><path d="M8 12H3" /></svg
>
Filters
{/snippet}
<h3>A little more control</h3>
<p>Show notifications in your personal feed.</p>
<div class="row">
<Switch label="Popover notifications" bind:checked={notifications} />
<span>Notifications</span>
</div>
</Popover>
<style>
h3 {
margin: 0;
font-size: 18px;
font-weight: 500;
}
p {
font-size: 14px;
line-height: 23px;
color: var(--portal-muted);
}
.row {
display: flex;
align-items: center;
gap: 14px;
}
</style>
API reference
These tables list the props and snippets that Popover declares. Attributes passed through to an element or primitive are listed under Forwarded attributes, not here.
Props
| Name | Type | Default | Required | Binding | Description |
|---|---|---|---|---|---|
open | boolean | false | No | Bindable | Whether the popover is open. |
label | string | None | Yes | One-way | Names the trigger and the popover content. Both use it as `aria-label`. |
align | 'start' | 'center' | 'end' | end | No | One-way | Alignment against the trigger. |
side | 'top' | 'right' | 'bottom' | 'left' | bottom | No | One-way | Preferred side of the trigger. |
sideOffset | number | 12 | No | One-way | Distance from the trigger in pixels. |
theme | 'light' | 'dark' | light | No | One-way | Theme scope for the portaled content. Portaled content does not inherit the page scope. |
triggerClass | string | Secondary 40px icon button | No | One-way | Replaces the trigger classes. The default is a secondary 40px icon button. |
Snippets
| Name | Type | Default | Required | Binding | Description |
|---|---|---|---|---|---|
trigger | Snippet | None | Yes | One-way | The trigger content, usually an icon. |
children | Snippet | None | No | One-way | The popover content. |
Forwarded attributes
None. Popover forwards no attributes.
The primitive underneath is a Bits UI peer dependency. Its own options are documented in the Bits UI Popover documentation. Only the props listed on this page are part of the Popover contract. No data attributes are documented as stable.
Limits
- Only `open` of Bits UI `Popover.Root` is wrapped. Other root options and callbacks are not exposed.
- Collision padding is fixed at 16px.
- `label` replaces the visible trigger text as the accessible name.