> For the complete documentation index, see [llms.txt](https://analog.groupthought.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://analog.groupthought.com/reference/alpine/popup.md).

# x-popup

Directives and a magic for small overlays that open next to a target element.

Directives and a magic for small overlays that open next to a target element.

| Directive / magic             | What it does                                                                                                    |
| ----------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `x-popup`                     | The root. Uses `x-disclosure` for its open state                                                                |
| `x-popup.noanimate`           | Skips waiting for CSS animations on open and close                                                              |
| `x-popup.noreturn`            | Leaves focus where it is when Escape closes the popup                                                           |
| `x-popup.noclose`             | Disables auto-close: Escape, click outside, focus outside                                                       |
| `x-popup="{ isOpen: false }"` | Options object, or a bare boolean. `isOpen` accepts a get/set pair                                              |
| `x-popup:popup`               | The panel. Modifiers are `x-float` positioning modifiers (default `bottom.auto`)                                |
| `x-popup:popup.nofloat`       | Disables floating; position the panel yourself                                                                  |
| `x-popup:target`              | The element the panel floats next to (`aria-expanded`, `aria-controls`)                                         |
| `x-popup:button`              | Toggles the popup on click; also acts as the target (`aria-haspopup`)                                           |
| `x-popup:float-reference`     | Optional: float next to this element instead of the target                                                      |
| `x-popup:arrow`               | The arrow element                                                                                               |
| `$popup`                      | `isOpen` (get/set), `open()`, `close()`, `targetEl`, `popupEl`, `floatReferenceEl`, plus everything on `$float` |

While the popup is open, Escape closes it and returns focus to the target (`.noreturn` skips the return), and a click or focus that lands outside the popup and its target closes it (`.noclose` disables all three). The target announces its expanded state and what it controls, and the panel is labelled by the button.

## Examples

### A basic popup

Use `x-popup:button` and `x-popup:popup` to toggle a floating panel:

```html
<div x-popup>
  <button x-popup:button>Share</button>
  <div x-popup:popup x-cloak class="absolute z-30 bg-canvas shadow">
    …
  </div>
</div>
```

The share block uses this shape as its fallback when the device has no native share sheet. Give the panel `x-cloak` so it stays hidden until Alpine starts.

### Positioning the panel

Pass `x-float` modifiers on `x-popup:popup` to pick the side, offset, and overflow behavior:

```html
<div x-popup:popup.bottom.offset.5px.flip.shift.update.pad.5px x-cloak>…</div>
```

The `core-popover` snippet builds its modifier string this way from its `position` and `offset` parameters. The full modifier list lives on the [x-float](/reference/alpine/float.md) page.

### An arrow

Use `x-popup:arrow` inside the panel to point at the target:

```html
<div x-popup:popup.bottom.offset.8px x-cloak>
  <div x-popup:arrow class="h-r6 w-r6">…</div>
  …
</div>
```

The float system positions the arrow on the side facing the target. `core-popover` uses a rotated square clipped to a triangle.

### Floating next to a different element

Use `x-popup:float-reference` to position against an element other than the trigger:

```html
<button x-popup:button>Share</button>

<!-- Force the panel to match this element's width -->
<span class="block w-full" aria-hidden="true" x-popup:float-reference></span>
```

The share block does this to size its panel to the block's full width while the trigger stays a small button. The target keeps the ARIA wiring; only the geometry moves.

### Driving the popup from outside

Use a get/set pair for `isOpen` to bind the popup to your own state:

```html
<div
  x-popup="{
    get isOpen() { return this.isTooltipVisible },
    set isOpen(value) { this.isTooltipVisible = value }
  }"
>
  …
</div>
```

Hotspot tooltips use this binding because hovering or tapping the dot changes the state directly. Anything inside the root can also call `$popup.open()` and `$popup.close()`.

## Options

| Option   | What it does                                                                            |
| -------- | --------------------------------------------------------------------------------------- |
| `isOpen` | Whether the popup is open (default `false`). Accepts a get/set pair for two-way binding |

Positioning modifiers on `x-popup:popup` pass to [x-float](/reference/alpine/float.md). The open state is an [x-disclosure](/reference/alpine/disclosure.md). Use [x-popover](/reference/alpine/popover.md) for the browser's top layer and focus trap. Use [x-menu](/reference/alpine/menu.md) or [x-select](/reference/alpine/select.md) for menus and form controls.
