Coupon
couponDisplays discount value, conditions, validity, and claim or used state.
Usage
Coupon type
kind defines the offer: amount for money off, discount for a percentage discount, and shipping for free delivery.
<div className="grid max-w-md gap-3">
<Coupon kind="amount" amount={50} threshold={299} title="Universal discount coupon for the entire site" scope="Supports all categories" validUntil="Valid before 2026.06.30" onClaim={() => {}} />
<Coupon kind="discount" discount={8.5} threshold={199} tone="danger" title="Digital exclusive discount coupon" scope="Digital only 3C" validUntil="Valid within this week" onClaim={() => {}} />
<Coupon kind="shipping" tone="neutral" title="Nationwide free shipping coupon" scope="Except for remote areas" validUntil="Long-term effective" onClaim={() => {}} />
</div>Status transfer
status Driver operating area copy and gray: Available → Received and ready for use → Used / Expired.
<div className="grid max-w-md gap-3">
<Coupon kind="amount" amount={20} threshold={99} title="Can be collected" status="available" onClaim={() => {}} />
<Coupon kind="amount" amount={20} threshold={99} title="Received and ready for use" status="claimed" onUse={() => {}} />
<Coupon kind="amount" amount={20} threshold={99} title="Already used" status="used" />
<Coupon kind="amount" amount={20} threshold={99} title="Expired" status="expired" />
</div>Scanning guide
shine allows the denomination area to periodically pass through the highlight band to guide users to receive it; used/expired coupons are automatically not displayed.
<Coupon kind="amount" amount={50} threshold={299} title="Limited time discount coupon" scope="Supports all categories" validUntil="Valid before 2026.06.30" shine onClaim={() => {}} />Settlement and Selection
Pass onSelect to make the entire coupon clickable, and selected to highlight ring for coupon selection on the settlement page.
<div className="grid max-w-md gap-3">
<Coupon kind="amount" amount={30} threshold={199} title="Settlement Selection (Selected)" status="claimed" selected onSelect={() => {}} />
<Coupon kind="discount" discount={9} threshold={0} title="Settlement Selection (Not Selected)" status="claimed" onSelect={() => {}} />
</div>When to use
Use Coupon for a complete commerce voucher with value, eligibility, validity, claim, use, or selection actions. Use [[Badge]] or Tag for a simple textual state.
Import
import { Coupon } from "@hulianui/ui"Props
| Name | Type | Default | Description |
|---|---|---|---|
| kind | "amount" | "discount" | "shipping" | "amount" | Amount-off, percentage discount, or free shipping. |
| amount | number | — | Amount value for amount coupons. |
| discount | number | — | Discount such as 8.5 for discount coupons. |
| threshold | number | — | Minimum spend; zero or omission means no threshold. |
| status | "available" | "claimed" | "used" | "expired" | "available" | Lifecycle state controlling action and disabled styling. |
| tone | "brand" | "danger" | "neutral" | "brand" | Color tone. |
| size | "sm" | "md" | "md" | Size. |
| shine | boolean | false | Animated claim highlight, automatically off after use or expiry. |
| selected | boolean | — | Checkout selection ring. |
| actionLabel | string | — | Overrides action text. |
| className | string | — | Root class. |
Events
| Event | Type | Description |
|---|---|---|
| onClaim | () => void | Available-state action. |
| onUse | () => void | Claimed-state action. |
| onSelect | () => void | Independent whole-coupon checkout selection. |
Slots
| Slot | Type | Description |
|---|---|---|
| title* | ReactNode | Coupon title. |
| scope | ReactNode | Applicable scope. |
| validUntil | ReactNode | Validity copy. |
Usage notes
- Used and expired states disable actions and shine automatically.
- Do not wrap the CSS ticket in overflow-hidden or its punched semicircles are clipped.
- Claim, use, and select map to different states and click regions.
- Built-in action, complete discount values, and eligibility labels follow
ConfigProvider locale; for example,discount={8.5}uses the native Chinese discount notation by default and renders15% offwithenUS.actionLabelstill has explicit precedence. Older dictionaries withoutformatDiscountsafely use the complete Chinese fallback.
Related
Sparkline · ImageViewer · LiveProductCard · DiffStat · ScoreRing · Badge
Playground
<Coupon kind="amount" amount={50} threshold={299} title="Universal coupon" status="available" onClaim={() => {}} />