Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Coupon Stacking Checkout Block for React

Discount codes applied in a fixed order for a soap and balm shop: percentage codes first, then fixed amounts, shipping last, at most three, with a stepped waterfall table from subtotal to total and a named reason when a code is refused.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Let shoppers stack codes by rule, with this coupon stacking checkout for React with Base UI. A compact header from Honeycomb Row, a soap and balm shop, sits over a wide hairline frame with a plus mark on each corner. The first band is a form: a labelled code Input that accepts what people paste (spaces dropped, capitals raised), an Add button and the rules in three plain lines. Below it a native table walks from the items subtotal, through shipping and each code in the order it applies, down to the total; each step has a bar, the change and the running figure, and the figures are the text equivalent of the bars. Three slots are always drawn, so adding or removing a code never moves the page. A code that breaks a rule is refused with its reason in the field's own line (unknown, already on the order, FOUNDER cannot be combined, three at most, or a fixed code's minimum not met after the percentages), and Remove takes a code out by name. Continue to payment is the only Shine Button. It's built from Field, Input, Button, Guides and a native table. For stackable offers, bundles and any checkout with more than one discount.

FAQ

Where do the stacking rules live?

In one pure function, refusalOf(ids, id), which returns the reason a code cannot join the order or an empty string. stackOf(ids) is the other: it applies the codes in order (percentage, then fixed, then shipping) to the items and shipping in whole cents and returns each step's change and running total. Edit CODES to change what exists, MOST to change the limit, and the alone and min fields for exclusive codes and minimums.

Why does the order of codes matter?

Percentage codes apply one after another, each to the amount the one before produced, so 15% then 10% is not 25%. Fixed amounts come next and cannot take the items below zero; free shipping is last and removes the shipping line. A fixed code can require a minimum to remain after the percentages, and a percentage code that would break an existing code's minimum is refused with that code's name.

Is the waterfall readable without seeing the bars?

Yes. The bars are drawn and hidden from assistive technology; the table is the content. Each row is a step with its name and what it does, the change and the running total, the table has a caption and the total row says how much the codes saved. An open slot reads "Nothing applied".

How does it look on a phone?

The bar column and the running column drop out and each step keeps its name, its change and a Remove button; the running total moves under the step's name. The status line and Continue to payment are pinned to the bottom of the screen.

Why are amounts whole cents?

Percentages are rounded once per step with Math.round on cents, and every figure is a sum of those integers, so the table always adds up to the total. usd is the only place cents become text.

What stays local in the demo, and how do I wire it up?

Everything. The codes are a typed list, nothing is looked up or applied to an order, and Continue to payment only says that payment comes next. In your app validate each code on the server with the same rules, return the stack it applied, and render that. To go to your payment step: give the Shine Button render set to an a element with nativeButton={false}.