Installation
Install the dependencies
pnpm add cn class-variance-authority github:sveltery/baseCopy the component
Copy the following files into src/lib/components/ui/popover.
<script lang="ts">
import type { ComponentProps } from 'svelte';
import { Popover as Primitive } from '@sveltery/base/popover';
import { cn } from 'cn';
let {
children,
class: classProp,
align = 'center',
alignOffset = 0,
side = 'bottom',
sideOffset = 4,
...props
}: ComponentProps<typeof Primitive.Popup> & Pick<ComponentProps<typeof Primitive.Positioner>, 'align' | 'alignOffset' | 'side' | 'sideOffset'> = $props();
</script>
<Primitive.Portal>
<Primitive.Positioner {align} {alignOffset} {side} {sideOffset} class="isolate z-50">
<Primitive.Popup data-slot="popover-content" {...props} class={cn('bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 flex flex-col gap-2.5 rounded-lg p-2.5 text-sm shadow-md ring-1 duration-100 data-[side=inline-start]:slide-in-from-right-2 data-[side=inline-end]:slide-in-from-left-2 z-50 w-72 origin-(--transform-origin) outline-hidden', classProp)}>
{@render children?.()}
</Primitive.Popup>
</Primitive.Positioner>
</Primitive.Portal><script lang="ts">
import type { ComponentProps } from 'svelte';
import { Popover as Primitive } from '@sveltery/base/popover';
import { cn } from 'cn';
let { children, class: classProp, ...props }: ComponentProps<typeof Primitive.Description> = $props();
</script>
<Primitive.Description data-slot="popover-description" {children} {...props} class={cn('text-muted-foreground', classProp)} /><script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from 'cn';
let { children, class: classProp, ...props }: HTMLAttributes<HTMLDivElement> = $props();
</script>
<div data-slot="popover-header" {...props} class={cn('flex flex-col gap-0.5 text-sm', classProp)}>
{@render children?.()}
</div><script lang="ts">
import type { ComponentProps } from 'svelte';
import { Popover as Primitive } from '@sveltery/base/popover';
import { cn } from 'cn';
let { children, class: classProp, ...props }: ComponentProps<typeof Primitive.Title> = $props();
</script>
<Primitive.Title data-slot="popover-title" {children} {...props} class={cn('font-medium', classProp)} /><script lang="ts">
import type { ComponentProps } from 'svelte';
import { Popover as Primitive } from '@sveltery/base/popover';
let { children, ...props }: ComponentProps<typeof Primitive.Trigger> = $props();
</script>
<Primitive.Trigger data-slot="popover-trigger" {children} {...props} />import { Popover as Primitive } from '@sveltery/base/popover';
export const Popover = Primitive.Root as typeof Primitive.Root;
export { default as PopoverTrigger } from './PopoverTrigger.svelte';
export { default as PopoverContent } from './PopoverContent.svelte';
export { default as PopoverHeader } from './PopoverHeader.svelte';
export { default as PopoverTitle } from './PopoverTitle.svelte';
export { default as PopoverDescription } from './PopoverDescription.svelte';Update the import paths
Change the imports to match your project setup.
Usage
<script lang="ts">
import { Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger } from '$lib/components/ui/popover';
</script><Popover>
<PopoverTrigger>Open</PopoverTrigger>
<PopoverContent>
<PopoverHeader>
<PopoverTitle>Dimensions</PopoverTitle>
<PopoverDescription>Set the dimensions for the layer.</PopoverDescription>
</PopoverHeader>
</PopoverContent>
</Popover>Bind open to read or change the state from outside.
<script lang="ts">
let open = $state(false);
</script>
<Popover bind:open>
<PopoverTrigger>Open</PopoverTrigger>
<PopoverContent side="right" align="start">Content</PopoverContent>
</Popover>API reference
Popover is styled on top of the Sveltery Base Popover primitive, which owns its positioning, focus handling and dismissal. PopoverContent renders the Base portal, positioner and popup, and takes the positioner's side, align, sideOffset and alignOffset props. See the Base UI Popover documentation for the behavior it ports.