Source Code

<div class="ass-wrap">
  <div class="ass-head">
    <h2>Pricing that fits how you work</h2>
    <div class="ass-toggle" role="tablist">
      <button type="button" class="ass-opt active" data-segment="individual" role="tab" aria-selected="true">Individuals</button>
      <button type="button" class="ass-opt" data-segment="team" role="tab" aria-selected="false">Teams</button>
      <span class="ass-thumb" id="assThumb"></span>
    </div>
  </div>

  <div class="ass-cards" id="assCards"><!-- populated by JS --></div>
</div>

Pricing with Audience Segment Switcher — Free Snippet

Pricing with Audience Segment Switcher · Pricing · Plain HTML, CSS & JS · Live preview

What's included

Features

Two fully independent plan datasets (individual vs team), not one template with conditionals
Sliding pill toggle with an animated single thumb element
Cross-fade transition on the entire card grid when switching segments
One cardHtml() renderer handles every plan regardless of which segment it belongs to
Special-cases a non-numeric "Custom" price for negotiated enterprise tiers
Featured-tier badge and highlighted border driven by a plan's featured flag
Per-user vs flat pricing units both supported via each plan's free-text "per" field
role="tablist" / aria-selected wired up for basic toggle accessibility
Export as HTML file, React JSX, or React + Tailwind CSS
Mobile (375px), Tablet (768px), Desktop device preview buttons

About this UI Snippet

Pricing with Audience Segment Switcher — Two Full Plan Sets, One Toggle

Screenshot of the Pricing with Audience Segment Switcher snippet rendered live

Most pricing toggles switch a billing period — monthly becomes annual, the same three plans just get cheaper. This snippet's toggle does something different: it switches the *audience*, and with it, an entirely different set of plans. "Individuals" shows a Starter/Plus/Pro lineup built around solo work; "Teams" shows a Team/Business/Enterprise lineup built around seats, permissions, and SSO. The two segments don't share a single plan — flipping the toggle is closer to visiting two separate pricing pages than adjusting one number.

A dataset per segment, not a template with conditionals

PLANS is a plain object with two keys, individual and team, each holding an array of plan objects with their own tier, tagline, price, per, features, cta, and featured fields. There is no shared plan template with an if (segment === 'team') branch buried inside it — each array is a complete, independently editable dataset. This matters because individual and team plans rarely differ by just a price: the feature sets, the number of tiers, and even the pricing unit (flat monthly vs. per-user-per-month) can all differ, and a shared-template approach would fight that reality.

`cardHtml()` renders any plan object the same way

Regardless of which segment it came from, every plan object is rendered by one cardHtml(plan) function that builds a card's markup from the plan's fields — including a special case for plan.price === 'Custom' (the Enterprise tier), which renders without a dollar sign, and a conditional ass-card-badge for whichever plan has featured: true. Because both segments' plan objects share the same shape, adding a segment or changing which plans have three vs. four tiers requires no changes to cardHtml() at all.

The cross-fade swap, not an instant re-render

Switching segments doesn't call renderSegment() directly — it goes through switchTo(), which first adds a .swapping class (opacity: 0, CSS-transitioned) to the card grid, waits 160ms for that fade-out to visually complete, *then* re-renders the grid's innerHTML with the new segment's cards and removes .swapping to fade back in. Re-rendering the DOM while the old cards are still fully visible would show a jarring instant content swap — even though the content change here is much larger than a single price update (going from a 3-tier layout to a possibly-differently-priced 3-tier layout with completely different copy), the same fade timing pattern smooths it out.

The sliding pill toggle

The two toggle buttons sit above an absolutely-positioned .ass-thumb element that slides between them via transform: translateX(100%), toggled by a .shift class — the same mechanic used for segmented iOS-style controls. This is deliberately decoupled from the card re-render: the thumb position update and the card content swap happen independently side by side, called from the same click handler.

Handling a plan with no numeric price

The Enterprise plan's price field is the string 'Custom' rather than a number. cardHtml() checks for this specific value and skips prefixing a dollar sign, so "Custom" renders on its own rather than as the nonsensical "$Custom". This is a common real-world requirement for enterprise tiers where price is negotiated, not published.

Extending to a third segment

Add a third key to PLANS (say, nonprofit) with its own array of plan objects, add a third .ass-opt toggle button with data-segment="nonprofit", and adjust the thumb's CSS width from calc(50% - 4px) to roughly a third — the same adjustment needed for a three-option toggle in general, since the current thumb math assumes exactly two segments.

Why this differs from a monthly/annual toggle

A monthly/annual toggle (see Pricing Toggle) recomputes one price on the same fixed set of plans. This snippet's toggle swaps the entire plan array — different tier names, different feature sets, sometimes a different number of tiers altogether — because "for individuals" and "for teams" describe genuinely different products, not just a different way of paying for the same one.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Rather than untangling a single template trying to serve two very different plan sets, paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain why PLANS is structured as two fully independent arrays instead of one shared array with per-plan conditionals for "individual" vs "team" fields — and what maintenance problems the conditional approach tends to cause as the two segments' plans diverge further over time. The same assistant is useful for extending the pattern: ask it to add a third audience segment and generalize the sliding-thumb math from a fixed 50% width to one computed from the number of options, or to make the fade-swap duration configurable. It can also help you think through whether a "Custom" priced tier needs a contact form modal wired to its CTA button rather than the same generic click handler as the other plans. 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:

text
Build a pricing section in plain HTML, CSS, and vanilla JavaScript with a two-option sliding pill toggle ("Individuals" / "Teams") that swaps the entire grid of pricing cards to a completely different, independently-defined set of plans — not just a price change on the same cards — no library.

Requirements:
- A JavaScript data object with two keys, each holding an array of plan objects (tier name, short tagline, price, billing-period label, an array of feature strings, a CTA button label, and a boolean marking whether it's the featured/most-popular tier). The two arrays should be free to have a different number of plans and different feature counts from each other.
- One shared rendering function that takes a single plan object and returns its card markup, used identically regardless of which segment array the plan came from. It must handle a plan whose price is the literal string "Custom" (for a negotiated enterprise-style tier) by omitting the dollar-sign prefix that every other numeric-priced plan gets.
- Clicking a toggle option must fade the current card grid to transparent via a CSS transition, and only after that transition's duration has elapsed, replace the grid's contents with the newly selected segment's rendered cards and fade the grid back to visible — not swap the content instantly while still opaque.
- The toggle itself should be a segmented control: two buttons layered over one absolutely-positioned sliding "thumb" element that animates from behind one button to behind the other via a CSS transform transition when the active option changes.
- The featured/most-popular card in whichever segment is showing should have a visually distinct border and a small badge, driven by that plan's own data field rather than a fixed card position.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Click Individuals or TeamsThe entire card grid cross-fades to a completely different plan set, not just updated prices on the same cards.
  2. 2
    Edit a segment's plansIn the JS panel, edit the array under PLANS.individual or PLANS.team — each plan object has tier, tagline, price, per, features, cta, and featured fields.
  3. 3
    Add or remove a tierAdd or delete a plan object from either array — cardHtml() renders however many plans exist with no other changes needed.
  4. 4
    Handle a custom/negotiated priceSet a plan's price field to the string "Custom" (as the Enterprise tier does) to skip the dollar-sign prefix.
  5. 5
    Add a third segmentAdd a new key to PLANS, a matching toggle button with a data-segment attribute, and adjust the thumb width/shift logic for three options.
  6. 6
    Export 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

Products sold to both solo users and teams
Dev tools, design tools, and productivity apps where individual and team buyers need genuinely different plan structures, not just a seat multiplier.
B2B2C platforms with distinct buyer types
Swap the same mechanic to "For Freelancers" vs "For Agencies" or "For Students" vs "For Institutions".
Marketplaces with buyer vs seller pricing
Use the segment switcher to show entirely different fee structures depending on which side of the marketplace a visitor represents.
Learn dataset-driven card rendering
Study how cardHtml() renders any plan shape from a data object rather than duplicating markup per tier.
Nonprofit / commercial dual pricing
Show a discounted nonprofit plan set alongside standard commercial pricing using the same segment pattern.
Related: Pricing FAQ
Pair with the Pricing FAQ beneath the cards to answer segment-specific billing questions.

Got questions?

Frequently Asked Questions

A monthly/annual toggle recomputes one price on the same fixed set of plans. This toggle swaps the entire array of plan objects — different tier names, different feature lists, sometimes a different number of tiers and even a different pricing unit (per-user vs flat) — because the two audiences represent genuinely different offerings, not just a different way of paying for the same plans.

Clicking a segment button first adds a .swapping class (opacity: 0, CSS-transitioned) to the card grid, then waits 160ms — matched to that transition's duration — before rewriting the innerHTML with the new segment's cards and removing .swapping to fade back in. Re-rendering the grid instantly, without this fade sequence, would show the old cards vanish and the new ones appear in the same frame, reading as a layout glitch rather than an intentional transition.

cardHtml() checks whether a plan's price field is exactly the string "Custom". If so, it renders that string directly with no dollar-sign prefix; every other plan's numeric price string gets a $ prepended. This lets a negotiated-price tier live in the same data array and render through the same function as every other plan.

Add a new key to the PLANS object (for example PLANS.nonprofit) holding its own array of plan objects in the same shape as the individual and team arrays, add a third toggle button with data-segment="nonprofit", and change the thumb's CSS width from calc(50% - 4px) to roughly a third of the toggle's width, since the current sliding-thumb math assumes exactly two segments.

Yes. Each segment is just an array under PLANS, and cardHtml() is mapped over whatever plans exist in that array with no assumption about a fixed count. One segment could have two plans and another could have four with no code changes required beyond editing the data.

Each plan object carries its own featured: true/false flag, and cardHtml() conditionally adds the .featured class and the "Most popular" badge based on that flag rather than always highlighting, say, the second card. This means the featured tier can be a different position (or absent entirely, as in the Enterprise-anchored team segment) per segment without touching the rendering logic.