---
title: Popover
description: Click-triggered floating content panel anchored to a trigger element.
sidebar:
  order: 2
search:
  tags: [floating panel, overlay, anchored, trigger]
---

# Popover

> Click-triggered floating content panel anchored to a trigger element.

## Import

```tsx
import { Popover } from 'moraine'
```

## Slot Structure

Wrapper trigger with a floating content portal containing the body.

```text
trigger
└── content (portal)
    └── body
```

## Examples

### Placements

Click trigger with four placement variants.

```tsx
function Placements() {
  const PLACEMENTS = ['top', 'right', 'bottom', 'left'] as const

  return (
    <div class="flex flex-wrap gap-3 items-center">
      <For each={PLACEMENTS}>
        {(placement) => (
          <Popover
            placement={placement}
            content={
              <div class="space-y-1">
                <p class="text-sm font-medium capitalize">{placement}</p>
                <p class="text-xs text-muted-foreground">Popover content aligned to {placement}.</p>
              </div>
            }
          >
            <Button variant="outline" size="sm">
              {placement}
            </Button>
          </Popover>
        )}
      </For>
    </div>
  )
}
```

### Hover Mode

Hover-based popover using open and close delays.

```tsx
function HoverMode() {
  return (
    <div class="flex flex-wrap gap-3 items-center">
      <Popover
        mode="hover"
        openDelay={180}
        closeDelay={120}
        content={
          <div class="space-y-1">
            <p class="text-sm font-medium">Hover Card</p>
            <p class="text-xs text-muted-foreground">
              This popover opens on hover and closes after delay.
            </p>
          </div>
        }
      >
        <Button variant="outline">Hover me</Button>
      </Popover>
    </div>
  )
}
```

### Dismiss Control

Prevent closing on outside interaction and Escape key.

```tsx
function DismissControl() {
  const [preventedCloseCount, setPreventedCloseCount] = createSignal(0)

  return (
    <div class="flex flex-wrap gap-3 items-center">
      <Popover
        defaultOpen
        dismissible={false}
        onClosePrevent={() => setPreventedCloseCount((value) => value + 1)}
        content={
          <div class="space-y-1">
            <p class="text-sm font-medium">Persistent popover</p>
            <p class="text-xs text-muted-foreground">
              Prevented close attempts: {preventedCloseCount()}
            </p>
          </div>
        }
      >
        <Button variant="secondary">Try close me</Button>
      </Popover>
    </div>
  )
}
```

## API Reference

### Attributes

#### `trigger`

Element users activate to open the popover.

##### ARIA Attributes

| Attribute | Type | Description |
| --- | --- | --- |
| aria-controls | boolean \| string \| undefined | References the controlled element while the related content is mounted. |
| aria-describedby | boolean \| string \| undefined | References descriptive text associated with the control. |
| aria-expanded | boolean \| string \| undefined | Indicates whether the controlled content is expanded. |

#### `content`

Positioned popover panel anchored to the trigger.

##### CSS Variables

| Attribute | Type | Description |
| --- | --- | --- |
| --mo-popper-content-transform-origin | string | CSS custom property exposed by this slot. |

##### Data Attributes

| Attribute | Type | Description |
| --- | --- | --- |
| data-placement | string \| undefined | State or slot attribute exposed for styling hooks and selectors. |

##### ARIA Attributes

| Attribute | Type | Description |
| --- | --- | --- |
| aria-describedby | boolean \| string \| undefined | References descriptive text associated with the control. |
| aria-labelledby | boolean \| string \| undefined | References the element that labels the control or region. |
| aria-modal | boolean \| string \| undefined | Identifies modal content that traps interaction outside the dialog. |
| role | string | Defines the semantic role exposed to assistive technology. |

#### `body`

Content body rendered inside the popover panel.

### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| children | JSX.Element | — | The reference element that triggers the popover. |
| class | ClassValue | — | Class applied to the component root or trigger element. |
| classes | PopoverT.Classes \| undefined | — | — |
| closeDelay | number \| undefined | 100 | Delay in milliseconds before closing in hover mode. |
| content | JSX.Element | — | Content to render inside the popover body. |
| defaultOpen | boolean \| undefined | — | — |
| dismissible | boolean \| undefined | — | — |
| forceMount | boolean \| undefined | — | — |
| id | string \| undefined | — | — |
| modal | boolean \| undefined | — | — |
| mode | PopoverMode \| undefined | click | Interaction mode for triggering the popover. |
| onClosePrevent | (() => void) \| undefined | — | — |
| onOpenChange | ((open: boolean) => void) \| undefined | — | — |
| open | boolean \| undefined | — | — |
| openDelay | number \| undefined | 100 | Delay in milliseconds before opening in hover mode. |
| placement | Placement \| undefined | — | — |
| preventScroll | boolean \| undefined | — | — |
| ref | JSX.HTMLElementTags["span"] extends { ref?: infer Ref; } ? Ref : never \| undefined | — | — |
| side | "bottom" \| "top" \| "right" \| "left" \| undefined | — | — |
| style | JSX.CSSProperties \| undefined | — | — |
| styles | PopoverT.Styles \| undefined | — | — |

### ARIA

Accessibility attributes and roles emitted by the component markup.

| Attribute | Type | Description |
| --- | --- | --- |
| aria-checked | boolean \| string \| undefined | Accessibility attribute forwarded by the rendered component. |
| aria-controls | boolean \| string \| undefined | References the controlled element while the related content is mounted. |
| aria-describedby | boolean \| string \| undefined | References descriptive text associated with the control. |
| aria-disabled | boolean \| string \| undefined | Indicates that the control is disabled. |
| aria-expanded | boolean \| string \| undefined | Indicates whether the controlled content is expanded. |
| aria-haspopup | boolean \| string \| undefined | Accessibility attribute forwarded by the rendered component. |
| aria-hidden | boolean \| string \| undefined | Hides decorative content from assistive technology. |
| aria-label | boolean \| string \| undefined | Provides an accessible label when visible text is not sufficient. |
| aria-labelledby | boolean \| string \| undefined | References the element that labels the control or region. |
| aria-modal | boolean \| string \| undefined | Identifies modal content that traps interaction outside the dialog. |
| role | string | Defines the semantic role exposed to assistive technology. |

### Data Attributes

State and slot attributes exposed for styling hooks and selectors.

| Attribute | Type | Description |
| --- | --- | --- |
| data-disabled | string \| undefined | Present when the component or item is disabled. |
| data-expanded | string \| undefined | State or slot attribute exposed for styling hooks and selectors. |
| data-highlighted | string \| undefined | Present when the item is highlighted by pointer or keyboard navigation. |
| data-placement | string \| undefined | State or slot attribute exposed for styling hooks and selectors. |
| data-positioned | string \| undefined | State or slot attribute exposed for styling hooks and selectors. |
| data-selected | string \| undefined | Present when the item is selected. |
| data-slot | string | Identifies the rendered slot for styling hooks and selectors. |
