# Alpine.js Plugins Reference

All plugins install via `Alpine.plugin(pluginName)` or CDN script before Alpine core.

## Intersect — viewport detection

```html
<!-- Trigger when element enters viewport -->
<div x-intersect="shown = true">
<div x-intersect:enter="shown = true">
<div x-intersect:leave="shown = false">

<!-- Modifiers -->
<div x-intersect.once="loadMore()">           <!-- fire once -->
<div x-intersect.half="animate()">            <!-- 50% visible -->
<div x-intersect.full="fullyVisible = true">  <!-- 99% visible -->
<div x-intersect.threshold.25="...">          <!-- custom % -->
<div x-intersect.margin.200px="...">          <!-- extend viewport boundary -->
```

## Focus — focus trapping

```html
<!-- Trap focus inside element (for modals/dialogs) -->
<div x-show="open" x-trap="open">
  <input type="text">
  <button @click="open = false">Close</button>
</div>

<!-- Modifiers -->
<div x-trap.inert="open">      <!-- aria-hidden on rest of page -->
<div x-trap.noscroll="open">   <!-- prevent body scroll -->
<div x-trap.noreturn="open">   <!-- don't restore focus on close -->
<div x-trap.noautofocus="open"> <!-- don't auto-focus first element -->
```

`$focus` magic: `$focus.first()`, `$focus.last()`, `$focus.next()`, `$focus.previous()`, `$focus.wrap()`.

## Persist — localStorage state

```html
<div x-data="{ count: $persist(0) }">
<div x-data="{ count: $persist(0).as('my-count') }">         <!-- custom key -->
<div x-data="{ count: $persist(0).using(sessionStorage) }">  <!-- session only -->
```

In `Alpine.data()` use `function()` (not arrow) to access `this.$persist()`.

## Mask — input formatting

```html
<input x-mask="(999) 999-9999">          <!-- 9=digit, a=alpha, *=any -->
<input x-mask="99/99/9999">
<input x-mask:dynamic="creditCardMask($input)">  <!-- dynamic mask -->
<input x-mask:dynamic="$money($input)">           <!-- currency -->
<input x-mask:dynamic="$money($input, ',', ' ')"> <!-- EU format -->
```

## Sort — drag-and-drop reordering

```html
<ul x-sort="handleSort($item, $position)">
  <li x-sort:item="1">
    <span x-sort:handle>drag handle</span>
    Item text
    <button x-sort:ignore>won't trigger drag</button>
  </li>
</ul>

<!-- Groups (drag between lists) -->
<ul x-sort x-sort:group="shared">...</ul>
<ul x-sort x-sort:group="shared">...</ul>

<!-- Ghost element styling -->
<ul x-sort.ghost>  <!-- style via .sortable-ghost CSS -->
```

## Anchor — element positioning

```html
<!-- Position relative to another element (uses Floating UI) -->
<div x-anchor="$refs.trigger">
<div x-anchor.bottom-start="$refs.trigger">
<div x-anchor.top-end.offset.10="$refs.trigger">
```

Positions: `top`, `top-start`, `top-end`, `bottom`, `bottom-start`, `bottom-end`, `left`, `right` + `-start`/`-end`.

## Morph — DOM diffing

```javascript
// Patch existing DOM with new HTML while preserving Alpine state
Alpine.morph(el, newHtml)
```

## Resize — element size observer

```html
<div x-resize="width = $width; height = $height">
<div x-resize.document="...">  <!-- observe document size -->
```
