# Popover

**An accessible popup anchored to a button.**

**Reference:** [View Source](https://github.com/jramke/fluid-primitives/tree/main/Resources/Private/Primitives/Popover) · [Zag.js Docs](https://zagjs.com/components/react/popover)

**Popover.html**

```html
<ui:popover.root>
    <ui:popover.trigger asChild="{true}">
        <ui:button>Open Popover</ui:button>
    </ui:popover.trigger>
    <ui:popover.content>
        <ui:popover.title>Notifications</ui:popover.title>
        <ui:popover.description>You are all caught up. Good job!</ui:popover.description>
    </ui:popover.content>
</ui:popover.root>

```

**Popover.ts**

```ts
import { mountAll } from 'fluid-primitives';
import { Popover } from 'fluid-primitives/popover';

mountAll('popover', ({ props }) => {
    const popover = new Popover(props);
    popover.init();
    return popover;
});

```

## Features

- Focus is managed and can be trapped within the popover
- Supports modal and non-modal modes
- Supports custom positioning with placement options
- Pressing `Escape` closes the popover
- Automatically adjusts position to stay in viewport

## Installation

```bash
typo3 ui:add popover
```

Or copy the files manually from GitHub (https://github.com/jramke/fluid-primitives.com/tree/main/packages/docs/Resources/Private/Registry/Popover) into your project.

Read more about installing [Components and Primitives](/docs/core-concepts/primitives.md).

## Examples

### With Close Button

Show a close button inside the popover.

**Popover.html**

```html
<ui:popover.root>
    <ui:popover.trigger asChild="{true}">
        <ui:button>Open Popover</ui:button>
    </ui:popover.trigger>
    <ui:popover.content showCloseButton="{true}">
        <ui:popover.title>Closeable</ui:popover.title>
        <ui:popover.description>Click the X button to close.</ui:popover.description>
    </ui:popover.content>
</ui:popover.root>

```

### Custom Positioning

Control where the popover appears relative to the trigger.

**Popover.html**

```html
<ui:popover.root positioning="{placement: 'right'}">
    <ui:popover.trigger asChild="{true}">
        <ui:button>Open Right</ui:button>
    </ui:popover.trigger>
    <ui:popover.content>
        <ui:popover.title>Right Position</ui:popover.title>
        <ui:popover.description>This popover opens to the right.</ui:popover.description>
    </ui:popover.content>
</ui:popover.root>

```

### Modal Mode

Make the popover modal to trap focus and block interaction with the rest of the page.

**Popover.html**

```html
<ui:popover.root modal="{true}">
    <ui:popover.trigger asChild="{true}">
        <ui:button>Open Modal Popover</ui:button>
    </ui:popover.trigger>
    <ui:popover.content>
        <ui:popover.title>Modal Popover</ui:popover.title>
        <ui:popover.description>Focus is trapped within this popover.</ui:popover.description>
    </ui:popover.content>
</ui:popover.root>

```

### Localization

Default close trigger labels are shipped via XLF and follow the current Site Language. For per-template overrides, pass translated strings through the `translations` prop. Set `closeTriggerLabel` to `{false}` or an empty string to omit the `aria-label`.

```html
<ui:popover.root
    translations="{
        closeTriggerLabel: f:translate(key: 'LLL:EXT:site_package/Resources/Private/Language/locallang.xlf:popover.close')
    }"
>
    ...
</ui:popover.root>
```

## API Reference

### popover.root

Provides popover state and context for the composed parts. Renders no wrapper element.

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `modal` | `boolean` | No | `false` | Whether the popover should be modal. |
| `portalled` | `boolean` | No | `true` | Whether the popover is portalled and proxies tabbing behavior regardless of DOM position. |
| `autoFocus` | `boolean` | No | `true` | Whether to automatically set focus on the first focusable content within the popover when opened. |
| `restoreFocus` | `boolean` | No | `true` | Whether to restore focus to the element that had focus before the popover was opened. |
| `closeOnInteractOutside` | `boolean` | No | `true` | Whether to close the popover when the user clicks outside of the popover. |
| `closeOnEscape` | `boolean` | No | `true` | Whether to close the popover when the escape key is pressed. |
| `positioning` | `array` | No | `-` | The user provided options used to position the popover content. |
| `defaultOpen` | `boolean` | No | `false` | The initial open state of the popover when rendered. Use when you don't need to control the open state of the popover. |
| `translations` | `array` | No | `-` | Localized popover labels. Set entries to `` to omit the corresponding `aria-label`. Use `f:translate` for per-template localization overrides when needed. |
| `rootId` | `string` | No | `-` | The root ID of the component, used for hydration and identification. |
| `ids` | `array` | No | `[]` | The IDs of of the component parts for composition. |
| `controlled` | `boolean` | No | `false` | If true, the component is meant to be initialized manually inside another component |

### popover.trigger

Opens and closes the popover. Renders a `<button>` element.

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `value` | `string` | No | `-` |  |
| `asChild` | `boolean` | No | `-` | If true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. |
| `class` | `string` | No | `-` | The CSS class(es) to be applied to the component. |
| `attributes` | `array` | No | `[]` | Additional attributes that should be rendered on the component where ui:attributes is used. |

#### Rendered data attributes

| Attribute | Description |
| --- | --- |
| `data-scope` | popover |
| `data-part` | trigger |
| `data-placement` | The placement of the trigger |
| `data-side` | The side of the trigger that the trigger is positioned on |
| `data-value` | The value of the item |
| `data-current` | Present when current |
| `data-state` | "open" \| "closed" |

### popover.positioner

Positions the popover content relative to the trigger. Renders a `<div>` element.

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `asChild` | `boolean` | No | `-` | If true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. |
| `class` | `string` | No | `-` | The CSS class(es) to be applied to the component. |
| `attributes` | `array` | No | `[]` | Additional attributes that should be rendered on the component where ui:attributes is used. |

### popover.content

Contains the popover panel content. Renders a `<div>` element.

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `asChild` | `boolean` | No | `-` | If true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. |
| `class` | `string` | No | `-` | The CSS class(es) to be applied to the component. |
| `attributes` | `array` | No | `[]` | Additional attributes that should be rendered on the component where ui:attributes is used. |

#### Rendered data attributes

| Attribute | Description |
| --- | --- |
| `data-scope` | popover |
| `data-part` | content |
| `data-state` | "open" \| "closed" |
| `data-nested` | popover |
| `data-has-nested` | popover |
| `data-expanded` | Present when expanded |
| `data-placement` | The placement of the content |
| `data-side` | The side of the trigger that the content is positioned on |

### popover.arrow

Displays a decorative arrow for the popover. Renders a `<div>` element.

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `asChild` | `boolean` | No | `-` | If true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. |
| `class` | `string` | No | `-` | The CSS class(es) to be applied to the component. |
| `attributes` | `array` | No | `[]` | Additional attributes that should be rendered on the component where ui:attributes is used. |

### popover.indicator

Displays a decorative state indicator. Renders a `<div>` element.

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `asChild` | `boolean` | No | `-` | If true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. |
| `class` | `string` | No | `-` | The CSS class(es) to be applied to the component. |
| `attributes` | `array` | No | `[]` | Additional attributes that should be rendered on the component where ui:attributes is used. |

#### Rendered data attributes

| Attribute | Description |
| --- | --- |
| `data-scope` | popover |
| `data-part` | indicator |
| `data-state` | "open" \| "closed" |

### popover.title

Provides the accessible title for the popover. Renders a `<div>` element.

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `asChild` | `boolean` | No | `-` | If true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. |
| `class` | `string` | No | `-` | The CSS class(es) to be applied to the component. |
| `attributes` | `array` | No | `[]` | Additional attributes that should be rendered on the component where ui:attributes is used. |

### popover.description

Provides supporting descriptive text for the popover. Renders a `<div>` element.

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `asChild` | `boolean` | No | `-` | If true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. |
| `class` | `string` | No | `-` | The CSS class(es) to be applied to the component. |
| `attributes` | `array` | No | `[]` | Additional attributes that should be rendered on the component where ui:attributes is used. |

### popover.closeTrigger

Closes the popover when activated. Renders a `<button>` element.

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `asChild` | `boolean` | No | `-` | If true the component uses its child only without the component template. Like Radix UI asChild or Base UI render props. |
| `class` | `string` | No | `-` | The CSS class(es) to be applied to the component. |
| `attributes` | `array` | No | `[]` | Additional attributes that should be rendered on the component where ui:attributes is used. |

### Machine JavaScript API

| Name | Type | Description |
| --- | --- | --- |
| `portalled` | `boolean` | Whether the popover is portalled. |
| `open` | `boolean` | Whether the popover is open |
| `setOpen` | `(open: boolean) => void` | Function to open or close the popover |
| `triggerValue` | `string \| null` | The trigger value |
| `setTriggerValue` | `(value: string \| null) => void` | Function to set the trigger value |
| `reposition` | `(options?: Partial<PositioningOptions>) => void` | Function to reposition the popover |

### Accessibility

| Key | Description |
| --- | --- |
| `Space`  | Opens/closes the popover. |
| `Enter`  | Opens/closes the popover. |
| `Tab`  | <span>Moves focus to the next focusable element within the content.<br /><strong>Note:</strong> If there are no focusable elements, focus is moved to the next focusable element after the trigger.</span> |
| `Shift + Tab`  | <span>Moves focus to the previous focusable element within the content<br /><strong>Note:</strong> If there are no focusable elements, focus is moved to the trigger.</span> |
| `Esc`  | <span>Closes the popover and moves focus to the trigger.</span> |

## Anatomy

```html
<primitives:popover.root>
    <primitives:popover.trigger />
    <primitives:popover.positioner>
        <primitives:popover.content>
            <primitives:popover.arrow />
            <primitives:popover.closeTrigger />
            <primitives:popover.title />
            <primitives:popover.description />
        </primitives:popover.content>
    </primitives:popover.positioner>
</primitives:popover.root>
```
