Popover
Display rich content in a floating panel anchored to a trigger element. Supports positioning, alignment, arrows, focus trapping, and dismissible behavior.
Playground
Experiment with different props in real-time.
Basic Usage
Place a trigger element as a child and use the content snippet for the popover body.
<script lang="ts">
import { Popover, Button } from 'sv5ui';
</script>
<Popover>
<Button>Open Popover</Button>
{#snippet content({ close })}
<div class="p-4 space-y-2">
<p class="text-sm font-medium">Popover Title</p>
<p class="text-sm text-on-surface/60">This is some popover content.</p>
<Button onclick={close} size="sm" variant="soft">Close</Button>
</div>
{/snippet}
</Popover>Positions
Use the side prop to control which side of the trigger the popover appears on.
<Popover side="top">
<Button variant="outline">Top</Button>
{#snippet content()}
<div class="p-3 text-sm">Top popover</div>
{/snippet}
</Popover>
<Popover side="right">
<Button variant="outline">Right</Button>
{#snippet content()}
<div class="p-3 text-sm">Right popover</div>
{/snippet}
</Popover>
<Popover side="bottom">
<Button variant="outline">Bottom</Button>
{#snippet content()}
<div class="p-3 text-sm">Bottom popover</div>
{/snippet}
</Popover>
<Popover side="left">
<Button variant="outline">Left</Button>
{#snippet content()}
<div class="p-3 text-sm">Left popover</div>
{/snippet}
</Popover>With Arrow
Set arrow to show a directional arrow, or pass an object to customize its dimensions.
<Popover arrow>
<Button>With Arrow</Button>
{#snippet content()}
<div class="p-4">
<p class="text-sm">This popover has an arrow pointing to the trigger.</p>
</div>
{/snippet}
</Popover>
<Popover arrow={{ width: 16, height: 8 }}>
<Button variant="outline">Custom Arrow</Button>
{#snippet content()}
<div class="p-4">
<p class="text-sm">This popover has a custom-sized arrow.</p>
</div>
{/snippet}
</Popover>Alignment
Use the align prop to control the alignment relative to the trigger.
<Popover align="start">
<Button variant="outline">Start</Button>
{#snippet content()}
<div class="p-3 text-sm">Aligned to start</div>
{/snippet}
</Popover>
<Popover align="center">
<Button variant="outline">Center</Button>
{#snippet content()}
<div class="p-3 text-sm">Aligned to center</div>
{/snippet}
</Popover>
<Popover align="end">
<Button variant="outline">End</Button>
{#snippet content()}
<div class="p-3 text-sm">Aligned to end</div>
{/snippet}
</Popover>With Form Content
Popover content can contain interactive form elements like inputs, selects, and buttons.
<script lang="ts">
import { Popover, Button, Input, Select, FormField } from 'sv5ui';
let name = $state('');
let framework = $state('svelte');
const frameworks = [
{ value: 'svelte', label: 'Svelte' },
{ value: 'react', label: 'React' },
{ value: 'vue', label: 'Vue' }
];
</script>
<Popover>
<Button>Edit Settings</Button>
{#snippet content({ close })}
<div class="w-72 space-y-4 p-4">
<p class="text-sm font-semibold">Settings</p>
<FormField label="Name" size="sm">
<Input bind:value={name} placeholder="Enter name" size="sm" />
</FormField>
<FormField label="Framework" size="sm">
<Select items={frameworks} bind:value={framework} size="sm" />
</FormField>
<div class="flex justify-end gap-2">
<Button onclick={close} variant="outline" size="sm">Cancel</Button>
<Button onclick={close} size="sm">Save</Button>
</div>
</div>
{/snippet}
</Popover>Controlled
Use bind:open to control the popover state externally.
<script lang="ts">
import { Popover, Button } from 'sv5ui';
let open = $state(false);
</script>
<div class="flex items-center gap-4">
<Button onclick={() => open = !open} variant="outline">
{open ? 'Close' : 'Open'} Popover
</Button>
<Popover bind:open>
<Button>Trigger</Button>
{#snippet content({ close })}
<div class="p-4 space-y-2">
<p class="text-sm">Controlled popover</p>
<p class="text-sm text-on-surface/60">State: {open ? 'Open' : 'Closed'}</p>
<Button onclick={close} size="sm" variant="soft">Close</Button>
</div>
{/snippet}
</Popover>
</div>UI Slots
Use the ui prop to override classes on specific internal elements of the Popover.
| Slot | Description |
|---|---|
content | The popover content panel — controls background, border, shadow, and rounding |
arrow | The arrow element pointing to the trigger — controls size and color |
Snippets
Use Svelte 5 snippets to customize specific parts of the Popover.
| Snippet | Type | Description |
|---|---|---|
children | Snippet<[{ open: boolean }]> | Trigger element — receives open state |
content | Snippet<[{ open: boolean; close: () => void }]> | Popover panel content — receives open state and close function |
Props
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | false | |
onOpenChange | (open: boolean) => void | - | |
arrow | boolean | { width?: number; height?: number } | false | |
transition | boolean | true | |
dismissible | boolean | true | |
side | 'top' | 'right' | 'bottom' | 'left' | 'bottom' | |
sideOffset | number | 8 | |
align | 'start' | 'center' | 'end' | 'center' | |
trapFocus | boolean | true | |
portal | boolean | true | |
children | Snippet<[{ open: boolean }]> | - | |
content | Snippet<[{ open: boolean; close: () => void }]> | - | |
class | string | - | |
ui | Record<Slot, Class> | - |