Staaarter

Billing Payment Methods

A payment method management block for billing settings pages. Lists saved cards with a brand icon, masked last 4 digits, expiry date, a default badge, and an inline near-expiry warning. Each row exposes a set-default action and a remove action that asks for confirmation before deleting. Built with shadcn/ui Button and Badge components, Lucide icons, and Tailwind CSS.

By Staaarter Team
Billing
Updated April 18, 2026
Docs
Live preview

Docs

Installation

A real shadcn registry command, not a copy-paste stand-in: it fetches this block plus its button, badge dependencies and any missing npm packages, and installs them straight into your project.

npx shadcn add https://staaarter.com/r/billing-payment-methods.json

Prefer not to use the CLI? Copy the source from the Code toggle above into src/components/blocks/billing/billing4.tsx instead.

Usage

The file also exports billing4Demo, the exact props behind the preview above. Spread it to get a working section in one line, then replace it with your own data.

import { Billing4, billing4Demo } from "@/components/blocks/billing/billing4";

export default function Page() {
  return <Billing4 {...billing4Demo} />;
}

Props

PropTypeDefaultDescription
headingstring"Payment methods"Section heading above the list.
descriptionstringnoneOne-line description under the heading.
methodsPaymentMethodItem[]noneSaved payment methods to render, used to seed the component's internal state.
addHrefstring"#"Destination for the 'Add payment method' link.
addLabelstring"Add payment method"Label for the add-method link.
classNamestringnoneExtra classes for the outer section element.

Types

interface PaymentMethodItem {
  id: string;
  brand: "visa" | "mastercard" | "amex" | "discover" | "other";
  last4: string;
  expiryMonth: number;
  expiryYear: number;
  isDefault?: boolean;
  expiringSoon?: boolean;
}

Behavior notes

  • The methods prop only seeds initial state, the component copies it into useState so set-default and remove actions update the list on the client without a page reload.
  • Clicking 'Remove' doesn't delete immediately, it swaps that row's actions for an inline 'Remove this card? Confirm / Cancel' prompt, and only the Confirm click removes the item from state.
  • Clicking 'Set as default' moves the Default badge to that row and clears it from every other row in one state update.
  • The brand icon is looked up internally from a Record<CardBrand, LucideIcon> keyed by the plain 'brand' string on each item, no icon or component is ever accepted as a prop.
  • expiringSoon is a plain boolean on the data rather than computed from the current date, so the 'Near expiry' badge renders identically on the server and after client hydration.

Frequently asked questions