# Plan picker

External component for a pricing chooser. Layout and interaction are in the component. Every visible string is HTML in `data`.

Editors follow `cms-edit://customer/plan-picker`.

## When to use

- A page or article where the reader picks one plan, and each plan can have its own billing options, benefits, and signup link
- Create a new **Plan picker** external, or edit the `data` on one already on the page. Do not rebuild this with **Pricing plans**

## Fields

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| externalComponentType | Symbol | Yes | `Plan picker` |
| cmsLabel | Symbol | Yes | Internal name |
| data | Object | Yes | Plan picker JSON. See the plan picker playbook. |
| backgroundColour | Symbol | No | Band behind the picker. Cards stay white. |
| textColour | Symbol | No | Section text colour. Plan copy uses the component colours. |
| anchor | Symbol | No | Optional id for an in-page link |

Leave `heading` empty. The title is `data.titleHtml`.

## Data

One object. A plan has one or more billing options. Benefits and the CTA belong to the billing option, so two ways to pay can show different rows and different signup URLs.

HTML fields accept `strong`, `em`, `b`, `br`, `sup`, `sub`, `span`, `a` (http(s) or a site path), and simple inline `svg`. Scripts, event handlers, and `style` are removed. A `span` inside a benefit label renders as the smaller gray aside.

`accent` is `purple`, `green`, or `gray`. It colours the selected card, the price, and the check icons. The CTA has its own `tone` (`purple` or `green`) and `variant` (`solid` or `outline`).

`icon` on a benefit is `check`, `cross`, or `none`. Omit it to use a check for included rows and a cross for locked rows. A row expands only when it is included and has `detailHtml`.

`pillIcon` is `plane` or `none`. Omit `pillHtml` to hide the pill. Prices are HTML strings. Do not store Stripe ids. Plan ids are unique. Billing ids are unique within a plan. `defaultPlanId`, `defaultBillingId`, and `switchToId` must match ids that exist. The billing switch does not change the selected plan.

Invalid JSON renders as “This plan picker could not be loaded.”

## Page placement

Add the external to a page or article content stack. One entry can be reused on more than one page.
