# Paywall
> Generated from paywall.contract.json — do not edit by hand.

Wrap a pro-gated affordance; the shared upsell renders itself — the crown upgrade mark, title, one-sentence body, the fixed unlock line, and Upgrade + See all plans CTAs are baked in.

Tier: **leaf-lit**. Frameworks: HTML (paste-and-run, no build step) · React · Vue 3.

Surfaces: editor, dashboard, settings, audience.

## Props
| Prop | Type | Default | Notes |
| --- | --- | --- | --- |
| `feature-key` | string (snake_case) | `—` | Stable token (e.g. custom_survey_url) — drives analytics + DOM hooks. Required. |
| `feature-label` | string | `Pro feature` | Short noun-phrase title next to the crown (used as the popover title unless title is set) |
| `title` | string | `—` | Popover title override; falls back to feature-label. May wrap to two lines |
| `body` | string | `—` | Exactly one sentence describing the benefit of unlocking; ends with a period |
| `description` | string | `—` | Popover description override; falls back to body |
| `required-plan` | essential | pro | `pro` | Drives the unlock line and the analytics plan prop |
| `placement` | top | bottom | `top` | Popover side relative to the anchor |
| `trigger` | click | hover | `click` | How the popover opens; click-away + Escape close a click popover |
| `cta-label` | string | `Upgrade` | The positive CTA verb; override only with a clear reason |
| `plans-label` | string | `See all plans` | The secondary CTA label — routes to the full pricing page |
| `upgrade-url` | string (URL) | `ahaslides.com/pricing` | Where Upgrade navigates (new tab, noopener) |
| `plans-url` | string (URL) | `ahaslides.com/pricing` | Where See all plans navigates (new tab, noopener) |
| `slot (default)` | element | `upgrade mark` | The gated affordance = the anchor; omit it to use the crown upgrade mark as the anchor |
| `paywall-shown / paywall-upgrade / paywall-plans` | CustomEvent<{feature,plan}> | `—` | Analytics contract; paywall-upgrade + paywall-plans are cancelable (preventDefault to run your own flow) |

## Visual standard (measured)
- Upgrade mark: 16×16 purple circle (--aha-color-primary) + white crown — a focusable control with Default/Hover/Active states; the custom mark, not a Phosphor crown
- Popover: dark indigo surface #242442 (--aha-bg-dark-raised), 300px wide, 16px padding, radius 12; animates opacity + lift on open via the motion tokens
- Anatomy: header (crown + title) · body (one sentence + "Unlock with the <Plan> plan.") · footer (Upgrade + See all plans)
- Buttons: TWO shared <aha-button>s — Upgrade (variant=positive, green --aha-button-positive-bg) + See all plans (variant=secondary, re-themed for the dark surface); never hand-rolled
- Analytics: paywall-shown on open · paywall-upgrade before Upgrade nav · paywall-plans before See-all-plans nav — all { feature, plan }
- Behaviour: Upgrade opens ahaslides.com/pricing (new tab, noopener); See all plans opens plans-url; preventDefault either event to run your own flow. Esc / click-away close

## When to use
- **aha-paywall** — any feature locked behind a paid plan — editor affordance, share option, results feature, dashboard action
- **crown-badge anchor** — the feature has no natural clickable anchor (e.g. a field label) — omit the slot and the crown is the anchor
- **required-plan pro** — the default gate; use essential only for essential-tier features
- **never a bespoke upsell** — a hand-rolled upgrade modal/tooltip drifts from the presenter app — always this element

Feature label is a short noun phrase; body is exactly one sentence about the benefit (not "This is a Pro feature"); the unlock line is fixed — do not reword. Popover/placement mechanics defer to aha-design-overlays; a single plan-gated setting row lives in the Settings surface.
