Pricing Slider — Per-Seat Price Slider HTML CSS JS

Pricing Slider · Pricing · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Tiered volume pricing
A TIERS table gives bigger teams lower per-seat rates, like real SaaS pricing.
Plan changes with size
Name, accent, badge, note, and CTA all update as you cross tiers.
Live total
The price recomputes on every drag — answering "what will this cost me?".
Colour-filled track
A gradient fills the slider up to the thumb in the tier's colour.
Custom cross-browser thumb
Styled via ::-webkit-slider-thumb and ::-moz-range-thumb.
Top-tier handoff
The largest tier flips the CTA to Contact sales.
Single source of truth
Everything derives from the current tier for consistency.
Data-driven & no library
Edit the TIERS table to reprice — plain HTML/CSS/JS, zero dependencies.

About this UI Snippet

Pricing Slider — Drag Team Size to See the Plan, Per-Seat Rate, and Total

Screenshot of the Pricing Slider snippet rendered live

A pricing slider lets a prospect drag to their team size (or usage) and instantly see what they'd pay — turning a static pricing table into an interactive, personalised quote. This snippet builds it in plain HTML, CSS, and vanilla JavaScript, with tiered per-seat pricing, a plan name and accent colour that change with size, and a slider track that fills as you drag — no library.

Tiered, volume-based pricing

The pricing isn't flat: bigger teams get a lower per-seat rate, defined by a TIERS table (up to 5 seats → $12/seat Starter, up to 20 → $10 Team, and so on). tierFor(seats) finds the tier the current size falls into, and the total is seats × that tier's rate. Encoding volume discounts as a tier table — rather than a formula — makes the pricing easy to read, change, and match to your real plans, and it's how most SaaS per-seat pricing actually works.

The plan changes as you drag

Crossing a tier boundary doesn't just change the rate — the plan name, the accent colour, the badge, the note, and even the CTA all update (the top tier flips the button to "Contact sales"). Reflecting the whole plan identity from the slider position makes the interaction feel like exploring real plans, not just watching a number tick. Everything derives from the current tier, so it stays consistent.

A filled slider track

The native range input's track is filled up to the thumb with the tier's colour using a linear-gradient whose stop is the slider's percentage — recomputed on every input. This gives the standard "progress-filled" slider look (which native inputs don't provide) and ties the fill colour to the current tier, so the control itself reinforces which plan you're in. Custom thumb styling via ::-webkit-slider-thumb and ::-moz-range-thumb keeps it on-brand across browsers.

Live total, instantly

Dragging recomputes the seats, tier, per-seat rate, and total on every input event, so the big price updates in real time. Showing the live total (with the per-seat breakdown beneath) answers the prospect's actual question — "what will this cost *me*?" — far more effectively than a grid of fixed numbers, which research links to higher pricing-page conversion.

Data-driven and drop-in

Edit the TIERS table to match your plans and rates, change the slider range to your seat or usage limits, and wire the CTA to checkout with the current seat count. It's a clear reference for tiered pricing logic, a colour-filled range input, and slider-driven plan selection. A native <input type="range"> is also keyboard- and screen-reader-friendly out of the box — arrow keys nudge the value and the accessible name comes from a label — which a custom drag-to-position div slider would have to reimplement, so it's worth keeping the real range element even after the heavy visual restyling applied here.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to work through the tier lookup or the gradient-fill math by hand. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how tierFor walks the TIERS array to find the first tier whose upTo covers the current seat count, and how the linear-gradient background string on the range input is recalculated on every drag to visually fill the track up to the thumb. The same assistant can help optimize it, for example checking whether the tierFor loop scales fine for a much longer tiers table, or whether the update function does more DOM writes per input event than necessary. It's also useful for extending the effect: ask it to add a second slider for a usage-based dimension (like API calls) that combines with seat count into one total, animate the price number counting up or down instead of snapping instantly, or persist the last-selected seat count in the URL so a shared link opens at the same price. 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 per-seat pricing slider in plain HTML, CSS, and vanilla JavaScript using a native range input — no libraries.

Requirements:
- A single native input of type range representing team size (for example 1 to 100 seats), styled with a custom cross-browser thumb (webkit and moz pseudo-elements) so it looks intentional rather than like the browser default.
- A tiers table in JavaScript where each tier defines an upper seat-count boundary, a plan name, a per-seat dollar rate, an accent color, and a background tint — with a lookup function that returns the first tier whose boundary is greater than or equal to the current seat count.
- On every input event on the slider, recompute the current tier from the seat count, compute the total price as seats times that tier's per-seat rate, and update: the displayed plan name badge (text, background tint, and text color), the seat count display, the large total price display, a small note showing the per-seat rate, and a call-to-action button whose label and background color both reflect the current tier.
- Visually fill the slider's track up to the current thumb position using a CSS linear-gradient set as the input's inline background style, recalculated on every drag so the filled portion's color matches the current tier's accent color and the unfilled portion stays a neutral gray.
- Make the highest tier's call-to-action button say "Contact sales" instead of a "Start [Plan]" label, since enterprise-scale seat counts typically require a sales conversation rather than instant self-serve checkout.
- Keep the whole thing keyboard-accessible by using the real native range input (not a custom div-based slider) so arrow keys and screen readers work without any extra code.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA pricing card renders with a team-size slider and a live total.
  2. 2
    Drag the sliderAs you change team size, the plan, per-seat rate, total, and accent update live.
  3. 3
    Cross a tierPassing a tier boundary changes the plan name, colour, and CTA (top tier → Contact sales).
  4. 4
    Edit the tiersChange the TIERS table to your plans, seat caps, and per-seat rates.
  5. 5
    Set the rangeAdjust the slider min/max to your seat or usage limits.
  6. 6
    Wire checkoutSend the current seat count to your checkout from the CTA handler.

Real-world uses

Common Use Cases

SaaS per-seat pricing
Let teams find their price by size — pair with a pricing page for plan details.
Usage-based pricing
Slide usage (API calls, storage) to a cost, alongside a usage calculator for multi-input estimates.
Plan recommendation
Guide prospects to the right tier from a single slider, next to a plan selector.
Quote and estimate widgets
Interactive quotes on a landing page.
Upgrade prompts
Show the cost of adding seats in-app.
Learning tiered pricing logic
A reference for tier lookups and filled range inputs — compare with a pricing toggle.

Got questions?

Frequently Asked Questions

A TIERS table lists, for each tier, the maximum seats it covers and the per-seat rate (smaller for bigger teams). tierFor(seats) returns the first tier whose upTo is at least the current seat count, and the total is seats × that tier's per-seat rate. Using a table rather than a formula makes volume discounts easy to read and to match to your real published plans.

Native range inputs don't show a filled portion by default. The snippet sets the input's background to a linear-gradient with a hard stop at the current value's percentage — coloured up to the thumb, grey after — and recomputes that percentage on every input event. The stop colour is the current tier's accent, so the fill also signals which plan you're in. Custom thumb styling makes it consistent across browsers.

Updating the plan name, accent colour, badge, note, and CTA as the slider crosses tiers makes the interaction feel like exploring your actual plans, not just scrubbing a price. It connects the cost to a named plan with its own identity, which is more persuasive and informative than a bare number — and it sets up the top-tier "Contact sales" handoff for enterprise.

Read the current seat count (range.value) and tier in the CTA's click handler, then pass them to your checkout — e.g. redirect to Stripe with the right price ID and quantity, or open your signup with the seat count prefilled. For the top tier, route to a contact-sales form instead. The slider is the configurator; your checkout consumes its output.

Hold the seat count in state, derive the tier and total with a computed/useMemo, and bind them to the display and the slider's fill style. In React use useState with an onChange; in Vue v-model with computed; in Angular ngModel with a getter. The TIERS lookup and pricing math are framework-agnostic — only the state and bindings move into the framework.