shadcn.io is not affiliated with official shadcn/ui
Promo Code Popover Success Block for Vue
A checkout summary with its promo chip and the popover shown open: which items the code covers, the minimum it needs, the discount and the new total worked out from the items, and one button that removes or applies the code.
Installation
Overview
Show a shopper exactly what a promo code did, with this promo applied popover for Vue with Ark UI. The host is a checkout: a heading and one sentence, then a frame with a plus mark on each corner that holds the page, with a basket drawn in grey shapes and a real order summary beside it. The summary lists four items, a promo row, the subtotal, the discount and the total. The chip in the promo row, "SAVE20 applied", is an outline Button that opens a Popover: the code's terms, each item marked Eligible with a check or Not eligible with a minus (the gift card is excluded), the discount as a percent of the eligible items, and the new total, with a button to remove the code. For preview the popover is drawn open in place when the page loads; the chip opens the real one, with the same content. Removing the code puts the full total back in the summary, and the chip becomes Apply SAVE20. It's built from Button, Popover and Guides, with CSS only. For stores, checkouts and any basket with a code.
FAQ
Why is the popover already open, and what do I keep?
So you can see the maths without a click. On load the popover is a copy drawn in place under the chip: a native dialog element that isn't modal, so nothing is trapped or focused and the page around it keeps working. The chip opens the real Popover, with its own positioning, Escape and focus return, and the copy stays closed until a reload. Both show the same PromoMaths component and share the block's state. In your app keep the Popover and drop the copy: the "in-place" state, its dialog and the Escape effect.
How are the discount and the total worked out?
From the items, in whole cents. The eligible subtotal adds the items marked promo, the code only applies when that comes to MINIMUM or more, the discount is PERCENT of it rounded to a cent, and the new total is the subtotal minus the discount. The popover, the discount row and the total all read the same numbers, and the label "20% of $104.00" shows the figure the percentage was taken from. Edit ITEMS, PERCENT, MINIMUM and VALID_UNTIL; your server must apply the same rules, since this page only shows them.
What stays in the page, and how do I wire it for real?
Everything: no order exists and nothing is charged. Remove code and Apply code change the page's state, close the popover, return focus to the chip and say in a polite status line what the total is ("SAVE20 removed in this demo"). To wire it for real, validate the code on your server in toggleCode, take the discount and the total from its response, and show its reason in the popover when it refuses a code.
Is it usable with a keyboard and a screen reader?
Yes. The chip is a named button that opens the popover; Escape closes the popover and focus goes back to the chip, as it does after Remove code or Apply code. The table has a caption, column headers and row headers, eligibility is written in words with an icon (never colour alone), and the discount keeps its minus sign inside a left-to-right span with "Minus" in text for screen readers. The chip is the Button wrapped in PopoverTrigger with asChild; the popover is controlled with open and onOpenChange.
How are amounts and the end date written?
Amounts go through Intl.NumberFormat in a fixed en-US locale, each in a single left-to-right span so signs and digits keep their order on a right-to-left page. The end date is a fixed ISO string written with Intl.DateTimeFormat in UTC in a time element, never compared with the visitor's clock here: your server decides whether a code is still valid.