8pt

Pricing Toggle

Pricing Toggle•Pricing
Overview

A sliding billing-period toggle. Prices roll vertically without shifting the layout.

Plain HTML, CSS and a little vanilla JS, with no framework dependency. Copy the prompt into Claude Code, Cursor, Trae or Codex and the model adds Pricing Toggle to your project in your colors.

Where to use it

SaaS pricing pages, upgrade dialogs, plan comparisons and monthly / yearly toggles.

Install

With Builder, install it with the 8pt CLI or call it directly from an editor connected to 8pt MCP.

$ npm i -g @8pt-dev/cli && 8pt add pricing-toggle
mcp › Use 8pt MCP to call get_component("pricing-toggle")

Code

Source for Pricing Toggle. Motion uses only transform and opacity and respects the Reduce motion setting.

<div class="x-pt">
  <div class="x-pt__switch" role="tablist">
    <span class="x-pt__thumb" aria-hidden="true"></span>
    <button type="button" role="tab" aria-selected="true">Monthly</button>
    <button type="button" role="tab" aria-selected="false">Yearly</button>
  </div>
  <div class="x-pt__plans">
    <div class="x-pt__plan"><span>Nimbus Lite</span><b class="x-pt__price"><i>$12</i><i>$9</i></b><em>/ M</em></div>
    <div class="x-pt__plan x-pt__plan--hi"><span>Nimbus Crew</span><b class="x-pt__price"><i>$29</i><i>$24</i></b><em>/ M</em></div>
  </div>
</div>
.x-pt{display:grid;justify-items:center;gap:18px;color:var(--d-fg,#fff)}
.x-pt__switch{position:relative;display:grid;grid-template-columns:1fr 1fr;padding:4px;border-radius:10px;background:var(--d-card,#101016);border:1px solid var(--d-line,rgba(255,255,255,.1))}
.x-pt__switch button{position:relative;z-index:1;width:76px;height:32px;border:0;background:transparent;color:var(--d-muted,#a0a0ab);font:600 13px/1 var(--d-font,system-ui,sans-serif);cursor:pointer;transition:color .3s}
.x-pt__switch button[aria-selected=true]{color:var(--d-bg,#000)}
.x-pt__thumb{position:absolute;left:4px;top:4px;width:76px;height:32px;border-radius:7px;background:var(--d-fg,#fff);transition:transform .45s cubic-bezier(.3,1.4,.5,1)}
.x-pt.yearly .x-pt__thumb{transform:translateX(76px)}
.x-pt__plans{display:flex;gap:12px}
.x-pt__plan{display:grid;gap:6px;min-width:120px;padding:16px 18px;border-radius:14px;background:var(--d-card,#101016);border:1px solid var(--d-line,rgba(255,255,255,.1))}
.x-pt__plan--hi{border-color:color-mix(in srgb,var(--d-accent,#4D74FF) 70%,transparent)}
.x-pt__plan span{font:500 12px/1 var(--d-font,system-ui,sans-serif);color:var(--d-muted,#a0a0ab)}
.x-pt__plan em{font:12px/1 var(--d-font,system-ui,sans-serif);font-style:normal;color:var(--d-muted,#a0a0ab)}
.x-pt__price{display:grid;height:1.1em;overflow:hidden;font:700 28px/1.1 var(--d-font,system-ui,sans-serif);font-variant-numeric:tabular-nums}
…
const init = (root) => {
  const box = root.querySelector('.x-pt'), tabs = box.querySelectorAll('[role=tab]');
  tabs.forEach((t, i) => t.addEventListener('click', () => {
    box.classList.toggle('yearly', i === 1);
    tabs.forEach((x, j) => x.setAttribute('aria-selected', String(i === j)));
  }));
};
Subscribe to Builder to see the full source.See pricing

More pricing components

View all

Ticket Pricing

More components

View all

AI Prompt Composer

Film Strip Carousel

Auto Tab Showcase

Media Bento Grid

Agent Chat Window

Model Pill Marquee

Director Art Cards

Mac File Window

Keep exploring