More Pricing Snippets
Pricing Toggle — Free HTML CSS JS Monthly/Annual Snippet
Pricing Toggle · Pricing · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Pricing Toggle — Price Array Swap, CSS Knob Slide & Annual Discount Badge

A monthly/annual billing toggle is a standard conversion pattern on SaaS pricing pages. Annual billing usually saves 20-30% — the toggle lets users see both options without a page reload. The price change combined with a "Save X%" badge nudges users toward the annual plan.
The data structure
Two arrays hold the prices: const monthly = [9, 29, 79] and const annual = [7, 23, 63]. Each index corresponds to a pricing tier. switchBilling() toggles isAnnual and selects the right array: document.querySelectorAll('.price-num') iterates all price elements and updates each textContent with the corresponding array value.
The CSS toggle knob
The toggle button gains the .annual class on switch. CSS transitions the knob: .tog-btn { transform: translateX(0) } for monthly and .tog.annual .tog-btn { transform: translateX(28px) } for annual. The background colour also changes.
Active label highlighting
switchBilling() directly sets style.color on the Monthly and Annual label elements — active label gets #f1f5f9 (bright), inactive gets #475569 (dimmed). This communicates which billing cycle is currently selected.
The save badge
An .annual child of each price shows the discount percentage (Save 22%, Save 21%, etc.). It starts hidden and gains display: flex when the toggle activates annual. The percentage values are hardcoded in the HTML — update them to match your actual discount.
The two-array price swap
Two JavaScript arrays hold prices for each plan: const monthly = [0, 12, 39] and const annual = [0, 10, 31]. When the toggle fires, it reads the current isAnnual boolean and selects the correct array. It then iterates each .amount span and updates textContent with the corresponding price. The transition: color 0.2s on .amount creates a brief colour fade as the number changes, drawing the eye to the update.
The CSS knob animation
The toggle knob uses transform: translateX(20px) in the checked state versus translateX(0) in the unchecked state. The CSS transition: transform 0.2s eases the slide. No JavaScript position calculation — the toggle is pure CSS with JavaScript only for the price swap and label active-state class toggling.
The "Save 20%" badge
The annual label contains a badge chip that is always visible, even before the toggle is switched. This is a deliberate conversion pattern — showing the savings before the user interacts means they see the benefit immediately. The badge uses a green tinted background to communicate positive value.
Connecting to Stripe
Store two Stripe price IDs per plan: one for monthly and one for annual billing. On CTA click, read the isAnnual state and pass the matching priceId to stripe.redirectToCheckout(). The toggle state determines which billing cycle the user enters at checkout.
Build with AI
Build, Understand, Optimize, and Extend It With AI
You don't have to work out the price-swap and knob-slide interaction by hand. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how switchBilling reads the isAnnual boolean to pick between two parallel price arrays and why each price element gets a brief opacity fade and vertical shift during the swap rather than an instant text change. The same assistant can help optimize it, for example checking whether indexing into monthly and annual arrays by a fixed [1,2,3] literal is fragile if a plan is added or reordered, or whether the featured card's styling stays legible if the accent color changes. It's also useful for extending the effect: ask it to add a third billing option (like quarterly), animate the numeric digits rolling rather than fading, or wire each tier's button to a specific Stripe price ID that depends on both the tier and the current billing period. Treat the code less like a finished artifact and more like a starting point for a conversation.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build a monthly/annual pricing toggle for a three-tier pricing section in plain HTML, CSS, and vanilla JavaScript — no libraries.
Requirements:
- A pill-shaped toggle switch with a circular knob that slides between two positions via a CSS transform transition, plus a "Monthly" label and an "Annual" label with an always-visible "Save X%" badge, where the inactive label dims and the active label brightens whenever the toggle state changes.
- Two parallel JavaScript arrays, one holding monthly prices and one holding annual prices, indexed identically to the three pricing tier cards, so a single boolean flip determines which array is read.
- Clicking the toggle must: flip the boolean, add or remove a CSS class on the toggle button that drives the knob's slide animation, update both labels' visual emphasis, and update each of the three displayed prices by reading from the newly active array.
- Each displayed price number must play a brief transition when it changes — fade its opacity down and shift it slightly, swap the text content, then fade and shift it back — rather than the number changing instantly with no visual feedback.
- One of the three tier cards must be visually marked as the featured/recommended plan with a distinct accent border, a background gradient or glow, and a floating "Most popular" badge centered above its top edge.
- Every feature list item in each card must show a checkmark or a cross via CSS pseudo-elements (not typed characters), with excluded features additionally dimmed in color.Step by step
How to Use
- 1Click the toggleClick the Monthly/Annual toggle to switch between price arrays. The knob slides, labels dim/brighten, and the Save badges appear.
- 2Update pricesIn the JS panel, update the monthly and annual arrays to your actual prices. Each index corresponds to a pricing tier card.
- 3Update save percentagesIn the HTML panel, update the Save X% text in each .annual badge to match your actual annual discount.
- 4Update plan names and featuresIn the HTML panel, update the tier names (Starter, Pro, Team), the price labels, and the feature lists.
- 5Change the accent colourFind #6366f1 in the CSS and replace with your brand colour. Updates the toggle background, featured card, and save badge.
- 6Export in your formatClick "HTML" for a standalone file, "JSX" for a React component, or "Tailwind" for a React + Tailwind version.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
Two arrays hold the prices for each tier. switchBilling() picks the active array (isAnnual ? annual : monthly) and iterates document.querySelectorAll(".price-num") to set each element's textContent to the corresponding array value.
The .tog-btn has CSS transition: transform 0.2s. In the default state, transform: translateX(0). When .annual is added to .tog, the CSS rule .tog.annual .tog-btn { transform: translateX(28px) } slides it right.
Add a fourth value to both monthly and annual arrays. Add a fourth .card div to the HTML with matching structure. The querySelectorAll iteration picks it up automatically by index.
Store a currentRate variable. In switchBilling(), multiply each price by currentRate before displaying. Add a currency dropdown that updates currentRate and calls switchBilling() again to refresh displayed prices.
Add data-price-id attributes to each CTA button. In the button onclick, read the active billing cycle and the tier price ID, then call stripe.redirectToCheckout({ priceId }) with the appropriate ID from your Stripe dashboard.
Yes. Click "JSX" for a React component. Manage isAnnual in useState. Derive displayed prices as isAnnual ? annual[i] : monthly[i] in the render. The CSS toggle animations work unchanged.