Card Bill Pay

Reads back what a credit card payment amount really costs before Pay, so paying the minimum or a little short doesn't quietly trigger interest.

StopsMinimum due paid, interest charged anyway

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/card-bill-pay.json

The files land in your project. They're yours to edit.

Usage

card-bill-pay-usage.tsx
import { CardBillPay } from "@/components/ui/card-bill-pay"

<CardBillPay
  statement={statement}
  defaultValue={2413}
  now={NOW}
  options={{ monthlyRate: 3.75, lateFee: (owed) => (owed > 25000 ? 1300 : owed > 10000 ? 1000 : 500) }}
  onPay={async (amount) => {
    await new Promise((resolve) => setTimeout(resolve, 600))
    setResult(`Paid ₹${amount.toLocaleString("en-IN")}`)
  }}
/>

What it catches

  • Paying less than the total due, which loses the interest-free period
  • Paying only the minimum, shown as time and interest to clear the balance
  • Paying below the minimum or more than three days late (late fee and bureau reporting)
  • One-tap switch to paying the total

Props

CardBillPay props
PropTypeDefault
statement* (required)

The statement being paid.

CardStatement—
value

Controlled amount to pay.

number | null—
defaultValue

Initial amount when uncontrolled. Defaults to the total due.

number | null—
onValueChange

Called when the amount changes.

(amount: number | null) => void—
payDate

Day the payment lands, as "YYYY-MM-DD" or a day number. Defaults to today (from `now`, else the clock after mount).

string | number—
now

"Now" in epoch ms, for deterministic rendering.

number—
options

Card terms: monthly rate, GST, grace days, late fee, minimum due formula.

CardBillOptions—
locale

Locale for money and dates.

string"en-IN"
currency

ISO currency code.

string"INR"
onPay

Called on Pay. With anything short of the total, the first press asks again. May return a Promise.

(amount: number, readback: PaymentReadback) => void | Promise<void>—
messages

Any visible string.

Partial<CardBillPayMessages>—

* required. Also accepts the native props of <div> (className, aria-*, data-*…), passed through to it.

Accessibility

  • Amount choices are labelled options; the custom amount has a <label>
  • The amount field is described by the warning lines
  • Pay uses aria-disabled while pending or at zero; focus moves to the first fix
  • Status is announced in a role="status" region

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

This is a UX guard rail. Enforce on the server: Take the amount due, minimum and due date from the issuer's records, and make the payment idempotent.

  • Uses the statement figures and fee schedule you pass; issuers' terms differ
  • Interest projections are estimates and assume no new spending
  • Rules follow RBI's credit card directions for India only

Rules

Rules last verified:

Informational; check the official source and your card's terms. Checked: interest-free period needs the entire outstanding paid by the due date and is suspended while the previous bill is outstanding; late charges and bureau reporting only after more than three days past due. Copied components don't update themselves, so re-check after rule changes (see updating a component).

What it stops

Minimum due paid, interest charged anyway

Also known as

credit card bill · minimum due · total due · statement · interest free · late fee · cibil · cred

Field type

Dependencies

Pairs well with