# Modal

> Multi-trigger modal/popup for exit intent, timed offers, scroll triggers, and click-to-open. Supports nested islands (EmailCapture, etc.).

Canonical URL: https://fa7e86e3d553:3005/islands/engagement/modal

Multi-trigger modal/popup for exit intent, timed offers, scroll triggers, and click-to-open. Supports nested islands (EmailCapture, etc.).

**Category**: Engagement

## Props

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| trigger | enum | No | "delay" | When to show: "click", "exit_intent", "delay", "scroll", "event" |
| triggerValue | string | No | "5000" | Trigger config: ms for delay, px/% for scroll, event name for event, CSS selector for click |
| position | enum | No | "center" | Modal position: "center", "bottom", "right", "fullscreen" |
| size | enum | No | "md" | Size: "sm", "md", "lg", "xl", "full" |
| closable | boolean | No | true | Show close button |
| backdrop | boolean | No | true | Show backdrop overlay |
| animation | enum | No | "scale" | Enter animation: "fade", "slide-up", "slide-right", "scale" |
| showOnce | boolean | No | true | Only show once per session (uses localStorage) |
| storageKey | string | No | "_lx_modal" | localStorage key for show-once tracking |
| headline | string | No | - | Modal headline text |
| body | string | No | - | Modal body text |
| image | string | No | - | Hero image URL |
| triggerLabel | string | No | - | Button label (for trigger:"click") |
| triggerVariant | enum | No | "primary" | Trigger button style: "primary", "outline", "minimal", "ghost" |
| children | array | No | [] | Nested islands: `[{island: "EmailCapture", props: {...}}]` |

## Embed Example

```html
<lx-island name="Modal">
  <script type="application/json">
{}
  </script>
</lx-island>
```

## Trigger Types

**Exit Intent** (desktop: mouse leaves viewport, mobile: back button):
```html
<lx-island name="Modal">
  <script type="application/json">
{}
  </script>
</lx-island>
```

**Delay** (show after N ms):
```html
<lx-island name="Modal">
  <script type="application/json">
{}
  </script>
</lx-island>
```

**Scroll** (show when user scrolls past threshold):
```html
<lx-island name="Modal">
  <script type="application/json">
{}
  </script>
</lx-island>
```

**Click** (button triggers the modal):
```html
<lx-island name="Modal">
  <script type="application/json">
{}
  </script>
</lx-island>
```

## Events

| Event | Direction | Payload |
|-------|-----------|---------|
| modal:open | Emits | `{storageKey}` |
| modal:close | Emits | `{storageKey, dismissed: boolean}` |
| modal:converted | Emits | When a child island emits a conversion event |

## Tips

- Place in a **hidden section** (`class="hidden"`) for non-click triggers
- `showOnce: true` prevents annoying repeat popups
- Use different `storageKey` values for multiple modals on the same page
- `children` array lets you embed EmailCapture, countdown timers, or any island inside
- `position: "bottom"` creates a cookie-banner style popup
- `position: "right"` creates a slide-in panel
- The "ExitIntent" pattern is just this island with `trigger: "exit_intent"`
