Overlay
Popover
A floating panel anchored to a trigger element. Supports positioning, arrows, custom content, and controlled state.
Basic Usage
<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
Place on any side of the trigger.
<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
<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
Align to start, center, or end of 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>Form Content
Rich content inside the popover.
<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 for programmatic control.
State: closed
<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
| Slot | Description |
|---|---|
content | Main popover content |
arrow | Arrow element |
Snippets
| Snippet | Description |
|---|---|
children | Trigger element (receives open state) |
content | Popover content (receives open and close) |
Props
| Prop | Type | Default |
|---|---|---|
open | boolean | false |
arrow | boolean | ArrowProps | false |
transition | boolean | true |
portal | boolean | true |
dismissible | boolean | true |
side | 'top'|'right'|'bottom'|'left' | 'bottom' |
sideOffset | number | 8 |
align | 'start'|'center'|'end' | 'center' |
ref | HTMLElement | null | null |
class | string | - |
ui | Record<Slot, Class> | - |