# Popover

> An anchored panel that opens next to a trigger and holds interactive content — quick settings, a small form, more than a tooltip can carry.

- Package: `fancy-ui-svelte` (Svelte 5 + Tailwind CSS v4)
- Category: Overlays
- Tags: overlay, popover, anchored, disclosure, accessibility
- Docs: https://fancy-ui.rama.app/docs/components/popover
- Source: https://github.com/RamaHerbin/fancy-ui/tree/main/src/lib/fancy-ui/popover

## Import

```svelte
<script lang="ts">
  import { Popover } from 'fancy-ui-svelte';
</script>
```

Setup (once per project): `npm install fancy-ui-svelte`, then add `@import "fancy-ui-svelte/tailwind.css";` after `@import "tailwindcss";` in your main CSS file. Full guide: https://fancy-ui.rama.app/llms.txt

React: `import { Popover } from 'fancy-ui-react';` (same prop names; `class` becomes `className`, snippets become `ReactNode`).

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `open` | `boolean` | `false` | Whether the panel is open. Bindable |
| `onOpenChange` | `(open: boolean) => void` | — | Called with the new value whenever the panel opens or closes, however the change happened |
| `side` | `"top" \| "bottom" \| "left" \| "right"` | `"bottom"` | Side of the trigger to place the panel on. Flips when it would overflow |
| `align` | `"start" \| "center" \| "end"` | `"center"` | Alignment along the trigger's cross axis |
| `offset` | `number` | `8` | Gap in pixels between the trigger and the panel |
| `dismissible` | `boolean` | `true` | Whether Escape and an outside click close the panel |
| `class` | `string` | — | Additional CSS classes, merged onto the panel |
| `ref` | `HTMLDivElement \| null` | `null` | Bindable reference to the panel element |
| `sound` | `boolean` | `false` | Plays open when the trigger opens the panel and close on a dismissal, once the user has enabled sound |

## Snippets

| Snippet | Description |
| --- | --- |
| `trigger` | The trigger's content, rendered inside the real <button> this component owns and wires up |
| `children` | The panel's content |

## Examples

### Basic Usage

A Dimensions panel with two labelled fields, matching the mockup.

```svelte
<script lang="ts">
	import { Popover } from "fancy-ui-svelte";

	let width = $state("100%");
	let height = $state("25px");
</script>

<Popover sound class="w-[220px]">
	{#snippet trigger()}
		⚙ Options
	{/snippet}

	<span class="text-[13px] font-semibold">Dimensions</span>
	<div class="flex gap-2">
		<input
			bind:value={width}
			aria-label="Width"
			class="border-input bg-background text-foreground min-w-0 flex-1 rounded-[6px] border px-2 py-[5px] text-[12px]"
		/>
		<input
			bind:value={height}
			aria-label="Height"
			class="border-input bg-background text-foreground min-w-0 flex-1 rounded-[6px] border px-2 py-[5px] text-[12px]"
		/>
	</div>
</Popover>
```

### Sides

The panel placed on each of the four sides.

```svelte
<script lang="ts">
	import { Popover } from "fancy-ui-svelte";

	const sides = ["top", "right", "bottom", "left"] as const;
</script>

<div class="flex flex-wrap items-center gap-6">
	{#each sides as side (side)}
		<Popover sound {side}>
			{#snippet trigger()}
				{side}
			{/snippet}
			<span class="text-popover-foreground text-[12px]">Placed on {side}</span>
		</Popover>
	{/each}
</div>
```

### With Form

An interactive form inside the panel, closing itself on submit — bind:open plus focus-trapped input and button.

```svelte
<script lang="ts">
	import { Popover } from "fancy-ui-svelte";
	import { Button } from "fancy-ui-svelte";

	let open = $state(false);
	let email = $state("");
	let sent = $state("");

	function invite() {
		sent = email;
		email = "";
		open = false;
	}
</script>

<Popover sound bind:open class="w-[240px]">
	{#snippet trigger()}
		Invite a teammate
	{/snippet}

	<span class="text-[13px] font-semibold">Invite by email</span>
	<input
		bind:value={email}
		type="email"
		placeholder="email@example.com"
		class="border-input bg-background text-foreground w-full rounded-[8px] border px-3 py-[7px] text-[12px]"
	/>
	<Button size="sm" fullWidth onclick={invite}>Send invite</Button>
</Popover>

{#if sent}
	<p class="text-muted-foreground mt-2 text-[12px]">Invited {sent}.</p>
{/if}
```
