Buy Now Pay Later Selector — Free BNPL Checkout UI

Buy Now Pay Later Selector · Forms · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Native radio cards
Real radio inputs under styled cards give keyboard nav and form submission for free.
Computed installment schedule
Amounts and dates derive from the order total and today's date, never hardcoded.
Reveal, not just relabel
Selecting BNPL opens a dedicated schedule panel instead of a vague badge change.
"Due at checkout" clarity
The first installment is explicitly marked so today's charge is unambiguous.
Commitment-stating CTA
The submit button's label always names the exact payment plan about to be confirmed.
0% interest flag
A pinned badge reduces the perceived risk of the installment option.
Accessible disclosure
The schedule panel uses the hidden attribute, kept in sync with the real selection.
Tabular installment amounts
Monospaced numerals keep the schedule list visually steady.

About this UI Snippet

Buy Now Pay Later Selector — Radio Cards With a Live Installment Schedule

Screenshot of the Buy Now Pay Later Selector snippet rendered live

Offering "Pay in 4" alongside a full-payment option is now standard at checkout, and the interface challenge is showing the installment breakdown clearly the moment a shopper considers it — not burying it behind a tooltip. This snippet builds that BNPL selector as two radio cards, with the second revealing a dated payment schedule inline, a natural pairing with checkout form or multi-step checkout.

Two radio cards, one real form

Like this library's radio card group, each payment method is a <label> wrapping a visually hidden native radio and a styled .bnp-box — so the selection is keyboard-navigable and form-submittable by construction, with the checked-state styling handled entirely by the :checked sibling selector in CSS. No custom click-state JavaScript is needed for the core selection behavior.

The schedule is computed, not hardcoded

buildInstallments() divides the order total by four and generates four due dates two weeks apart starting today, formatting each with toLocaleDateString. Every installment amount and date is derived from ORDER_TOTAL and the current date rather than typed out — change the order total and the whole schedule (and the per-installment amount) recalculates correctly.

Reveal, don't just relabel

Selecting "Pay in 4" doesn't just highlight the card — it reveals a dedicated schedule panel (toggled via the hidden attribute) listing all four payments with their due dates, and marks the first as "Due at checkout" so it's unambiguous which payment happens right now versus later. This answers the two questions a shopper actually has before committing: how much, and when.

The submit button always states the real commitment

The primary button's label changes with the selection — "Continue · Pay in full today" versus "Continue · Pay in 4" — so the call-to-action itself confirms what's about to happen, rather than a generic "Continue" that leaves the payment plan ambiguous until the next screen.

Wiring it to a real BNPL provider

Replace the schedule computation with the actual plan returned by your BNPL provider's API (Klarna, Affirm, Afterpay all return an installment schedule with real dates and any provider fees), and gate the "Pay in 4" option behind that provider's approval check — show a brief loading state while the eligibility check runs, and fall back to "Pay in full" if the shopper isn't approved.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to work out the schedule math or the disclosure UX pattern on your own. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how buildInstallments() derives every payment amount and due date from the order total and the current date rather than hardcoding them, and why revealing a full dated schedule (with the first payment explicitly marked "due at checkout") communicates the commitment more clearly than just changing a badge or label. The same assistant can help optimize it — asking whether the fixed two-week installment cadence should instead come from a real BNPL provider's quote response, or whether the submit button's confirmation-then-reset sequence needs a genuine loading state once a real payment API is involved. It's also useful for extending the selector: ask it to add a third BNPL provider option with a different cadence, gate the BNPL option behind a live eligibility check, or add a small APR/fee disclosure required by regulation in some regions. 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 "Buy Now Pay Later" checkout payment selector in plain HTML, CSS, and JavaScript with no library or CDN dependency.

Requirements:
- A form containing two radio-card options (built the accessible way: a label wrapping a visually hidden native radio input and a styled sibling card, with all selected-state styling driven by the CSS :checked sibling selector) — one for "Pay in full" showing the full order total, and one for "Pay in 4" showing the per-installment amount and a 0%-interest badge.
- Selecting "Pay in 4" must reveal a payment-schedule panel (toggled via the HTML hidden attribute) listing four installments, each with a computed due date (spaced two weeks apart starting from today) and amount — all four amounts and dates must be calculated from the order total and the current date at render time, not hardcoded strings, so changing the order total recalculates every installment correctly.
- The first installment in the revealed schedule must be visually marked as due immediately (e.g. "Due at checkout") so it's unambiguous which payment happens today versus in the future.
- The form's submit button label must update to state the exact payment commitment based on the current selection (e.g. "Continue · Pay in full today" vs "Continue · Pay in 4") rather than staying a generic "Continue" — so the call-to-action itself always reflects what the user is about to confirm.
- On submit, prevent the default form submission, show a brief confirmation state on the button reflecting the chosen plan, then after a short delay revert to the normal selection-dependent label.

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
    Paste HTML, CSS, and JSTwo payment options render with "Pay in full" selected by default.
  2. 2
    Select "Pay in 4"A schedule panel reveals four installments, computed from the order total and today's date.
  3. 3
    Watch the submit buttonIts label updates to state exactly what will happen — pay in full today, or pay in 4.
  4. 4
    Switch back to full paymentThe schedule panel hides again and the button label reverts.
  5. 5
    Change the order totalUpdate ORDER_TOTAL — the installment amounts recompute automatically.
  6. 6
    Connect a real BNPL providerReplace buildInstallments() with the schedule your provider's API returns, gated by an eligibility check.

Real-world uses

Common Use Cases

E-commerce checkout
Offer BNPL alongside full payment, next to a promo code input and order summary.
Multi-step checkout flows
Slot this as the payment-method step inside a multi-step checkout.
Subscription upgrades
Let users split a large annual upgrade into installments.
High-ticket purchases
Show installment framing for electronics, furniture, or travel bookings.
Mobile checkout
The stacked card layout works cleanly on narrow viewports without a redesign.
A/B testing payment framing
Swap which option is pre-selected to test conversion impact of default framing.

Got questions?

Frequently Asked Questions

buildInstallments() divides ORDER_TOTAL by four for the per-installment amount, then generates four due dates spaced two weeks apart starting from today's date, formatting each with toLocaleDateString. Nothing about the schedule is hardcoded — change the order total and every installment amount recalculates, and the dates are always relative to whenever the page loads.

A shopper deciding on BNPL needs to see exactly how much and when each payment happens before committing — a relabeled badge doesn't answer that. The revealed schedule panel lists all four dated installments and explicitly marks the first as "Due at checkout" so there's no ambiguity about what charges immediately versus later.

Most providers return an actual installment plan (with real due dates and any provider fees) from an eligibility or quote API call made at checkout. Replace buildInstallments()'s local computation with that response, and gate showing the "Pay in 4" option behind the provider's approval check — show a brief loading state while checking eligibility, and hide or disable the option if the shopper isn't approved.

A generic "Continue" button leaves the actual payment commitment ambiguous until the next screen. Updating the label to state the exact plan — "Pay in full today" or "Pay in 4" — means the call-to-action itself confirms what's about to happen, reducing surprise (and support tickets) at the moment of commitment.

Hold the selected payment method in component state (radios still bind via value/checked or v-model), and derive the schedule panel's visibility and the submit button's label from that state. Compute the installment list in a memoized function fed by orderTotal, mirroring what buildInstallments() does directly to the DOM here.