webdevpuneet.com

Subscription Pause/Resume Flow — Free Billing State UI

Subscription Pause/Resume Flow · Cards · Plain HTML, CSS & JS · Live preview

CategoryCards

Copy & paste

Source Code

<div class="spr-card">
  <div class="spr-head">
    <div>
      <span class="spr-plan-label">Current plan</span>
      <h3 class="spr-plan-name">Studio Pro</h3>
    </div>
    <span class="spr-state" id="sprState">Active</span>
  </div>

  <div class="spr-row">
    <span>Next billing date</span>
    <b id="sprBillingDate">September 22, 2026</b>
  </div>
  <div class="spr-row">
    <span>Price</span>
    <b>$32.00 / month</b>
  </div>

  <div class="spr-toggle-wrap">
    <button type="button" class="spr-toggle" id="sprToggleBtn" role="switch" aria-checked="false">
      <span class="spr-toggle-track"><span class="spr-toggle-thumb"></span></span>
      <span class="spr-toggle-label" id="sprToggleLabel">Pause subscription</span>
    </button>
  </div>

  <div class="spr-pause-panel" id="sprPausePanel" hidden>
    <label class="spr-resume-label" for="sprResumeDate">Resume by</label>
    <input type="date" id="sprResumeDate" class="spr-date-input">

    <ul class="spr-info-list">
      <li><span class="spr-check">✓</span> You will not be charged while paused</li>
      <li><span class="spr-check">✓</span> Access continues until <b id="sprPeriodEnd">Sep 22</b>, then pauses</li>
      <li><span class="spr-check">✓</span> Auto-resumes on the date above, or resume anytime sooner</li>
    </ul>
  </div>

  <p class="spr-footnote" id="sprFootnote">Pausing keeps your data and settings — you won't lose anything.</p>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

True ARIA switch
role="switch" with aria-checked, not a styled checkbox pretending to be one.
Attribute-driven styling
Thumb position and track color read directly off aria-checked via CSS.
Consequence-first messaging
A three-line checklist states the no-charge, access, and auto-resume behavior inline.
Sensible date defaults
Resume date defaults 30 days out with a min of today.
Live date confirmation
Changing the resume date updates a human-readable footnote immediately.
Single state function
setPaused() is the one place that updates every dependent element.
Accessible panel toggling
The pause panel uses the hidden attribute, not a CSS-only display hack.
Status badge color-coding
Active (green) and Paused (amber) are visually distinct at a glance.

About this UI Snippet

Subscription Pause/Resume — A Toggle That Explains Its Own Consequences

Screenshot of the Subscription Pause/Resume Flow snippet rendered live

Pausing a subscription is a moment where ambiguity causes support tickets: will I be charged? Do I lose access immediately? When does it come back? This snippet builds a pause/resume card that answers all three questions inline, the moment the toggle flips, instead of hiding the consequences behind a separate help article — a pattern worth pairing with a subscription widget or pricing toggle in a billing settings page.

A real switch, not a decoration

The toggle is a <button role="switch" aria-checked> rather than a styled checkbox — role="switch" is the correct ARIA role for a control that represents an on/off state with an immediate effect (as opposed to a checkbox in a form awaiting submission). The thumb position and track color are driven entirely by the aria-checked attribute via CSS attribute selectors, so the visual state and the accessible state can never drift apart.

The panel that appears only explains, never confuses

Toggling to paused reveals a panel — hidden via the hidden attribute, not CSS-only — with a resume-by date picker and a three-line list, each prefixed with a checkmark, stating exactly what happens: no charge, access continues until period end, and auto-resume behavior. This is the core UX principle: don't just change a status label, restate the consequences at the moment the user needs to know them.

Resume date defaults sensibly

The date input defaults 30 days out and its min attribute is set to today, so a user can't accidentally pick a resume date in the past. Changing the date updates the footnote to a human-readable confirmation ("Your subscription will auto-resume on...") using toLocaleDateString, giving immediate feedback that the date was registered.

One function owns both states

setPaused(paused) is the single function that updates the switch, the status badge, the toggle's own label ("Pause" vs. "Resume"), the panel's visibility, and the footnote text — all from one boolean. This mirrors the same "one source of truth drives every dependent element" pattern used across this library, and makes it straightforward to call setPaused from a real API response instead of just a click handler.

Wiring it to real billing

Replace the toggle handler with an API call to your billing provider (Stripe subscriptions support a native pause-collection state), and only call setPaused once that call resolves — add a brief loading state on the toggle in between. Read the actual next-billing and period-end dates from your subscription object rather than the hardcoded strings here.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSAn active subscription card renders with plan, price, and next billing date.
  2. 2
    Click the toggleIt switches to "Paused" and reveals a resume-by date picker plus a plain-language explanation of billing behavior.
  3. 3
    Pick a resume dateThe date input defaults 30 days out and can't be set in the past; changing it updates the confirmation footnote.
  4. 4
    Click the toggle againIt resumes the subscription, hides the panel, and restores the default footnote.
  5. 5
    Wire real billing datesReplace BILLING_DATE_TEXT and PERIOD_END_SHORT with values from your subscription object.
  6. 6
    Connect the APICall your billing provider's pause/resume endpoint in the toggle handler before calling setPaused.

Real-world uses

Common Use Cases

SaaS billing settings
Let users pause instead of cancelling, with a true role="switch" toggle and a resume date defaulting to thirty days away.
Gym and membership apps
Handle seasonal pauses in gym and membership apps with plain language about whether billing continues and whether access ends immediately.
Meal kit and box subscriptions
Communicate exactly when the next box is due, using a three-line checklist covering charges, access and resume date.
Streaming and media plans
Pair with a pricing toggle for plan changes, with thumb and track styled straight from aria-checked.
Retention and billing support
Offer pause as an alternative in cancel flows, reducing will I be charged tickets, or add a subscription widget for management.

Got questions?

Frequently Asked Questions

role="switch" is the correct ARIA role for a control representing an on/off state that takes effect immediately, as opposed to a checkbox that typically awaits form submission. Using a real switch role means screen readers announce it correctly as "Pause subscription, switch, off" and toggling it, rather than describing it as a checkbox being checked.

The pause panel is hidden using the HTML hidden attribute, toggled by the single setPaused(paused) function — the same function that updates the switch, status badge, and toggle label. Because one function owns all of these, the panel can never be visible while the badge still reads "Active", or vice versa.

The date input's min attribute is set to today's date (new Date().toISOString().slice(0, 10)) on page load, which makes the browser's native date picker refuse to let users select an earlier date. The default value is also set 30 days out so there's a sensible starting point rather than an empty field.

Stripe subscriptions support a native pause_collection behavior. In the toggle's click handler, call your backend endpoint that sets or clears pause_collection on the subscription, show a brief loading state on the toggle while that request is in flight, and only call setPaused(true/false) once the API call resolves successfully — reverting the toggle and showing an error if it fails.

Hold isPaused and resumeDate in component state. Derive the switch's aria-checked, the status badge text/color, the panel's visibility, and the footnote all from isPaused in render — mirroring what setPaused() does directly to the DOM here. Make the toggle handler async so it can await a real billing API call before updating state.