Billing overview
A presentation-only billing summary with consumer-owned plan, billing status, renewal, payment details and actions.
Present billing context without owning billing logicLink to section
BillingOverviewPanel gives an application a compact billing summary while
keeping billing truth and every action in the consuming product. Use it to show
plan, billing cadence, status, renewal and payment information that your own
billing layer has already resolved.
Presentation only
The Block does not query Stripe, calculate billing periods, change a plan, open a portal, renew a subscription or authorize an action. Supply truthful values and connect actions through your own validated billing boundary.
Canonical identityLink to section
- Category: Commerce, slug
commerce. - Block:
billing-overview, exportBillingOverviewPanel. - Canonical source:
apps/marketing/content/blocks/commerce/billing-overview/. - Complete entry point:
index.tsx.
Copy sourceLink to section
Configure the public UI package and tokens, then create
src/components/blocks/billing-overview/index.tsx in your application.
Open the complete source below and use the code block copy button when available. If clipboard access is unavailable, select the code manually.
View and copy the complete source
import * as React from "react";
export type BillingOverviewPanelProps = Readonly<{
title: React.ReactNode;
description?: React.ReactNode;
planLabel: React.ReactNode;
planValue: React.ReactNode;
billingLabel?: React.ReactNode;
billingValue?: React.ReactNode;
statusLabel?: React.ReactNode;
statusValue?: React.ReactNode;
renewalLabel?: React.ReactNode;
renewalValue?: React.ReactNode;
paymentLabel?: React.ReactNode;
paymentValue?: React.ReactNode;
primaryAction?: React.ReactNode;
secondaryAction?: React.ReactNode;
className?: string;
}>;
/**
* Presentation-only billing summary. Billing truth and every action remain
* entirely owned by the consuming application.
*/
export function BillingOverviewPanel({
title,
description,
planLabel,
planValue,
billingLabel,
billingValue,
statusLabel,
statusValue,
renewalLabel,
renewalValue,
paymentLabel,
paymentValue,
primaryAction,
secondaryAction,
className,
}: BillingOverviewPanelProps) {
const id = React.useId();
const titleId = `${id}-title`;
const descriptionId = `${id}-description`;
const rootClassName = [
"min-w-0 space-y-6 rounded-xl border border-border bg-card p-5 text-card-foreground sm:p-6",
className,
]
.filter(Boolean)
.join(" ");
const details = [
{ label: planLabel, value: planValue },
billingLabel && billingValue
? { label: billingLabel, value: billingValue }
: null,
statusLabel && statusValue
? { label: statusLabel, value: statusValue }
: null,
renewalLabel && renewalValue
? { label: renewalLabel, value: renewalValue }
: null,
paymentLabel && paymentValue
? { label: paymentLabel, value: paymentValue }
: null,
].filter(
(
detail,
): detail is Readonly<{
label: React.ReactNode;
value: React.ReactNode;
}> => detail !== null,
);
return (
<section
aria-describedby={description ? descriptionId : undefined}
aria-labelledby={titleId}
className={rootClassName}
data-slot="billing-overview-panel"
>
<header className="min-w-0 space-y-2">
<h2 className="break-words text-xl font-semibold" id={titleId}>
{title}
</h2>
{description ? (
<div
className="break-words text-sm text-muted-foreground"
id={descriptionId}
>
{description}
</div>
) : null}
</header>
<dl className="grid min-w-0 gap-4 sm:grid-cols-2">
{details.map((detail, index) => (
<div
className="min-w-0 rounded-lg border border-border bg-background p-4"
key={index}
>
<dt className="text-sm font-medium text-muted-foreground">
{detail.label}
</dt>
<dd className="mt-1 break-words text-sm font-medium">
{detail.value}
</dd>
</div>
))}
</dl>
{primaryAction || secondaryAction ? (
<div className="flex min-w-0 flex-col gap-3 sm:flex-row sm:flex-wrap">
{primaryAction}
{secondaryAction}
</div>
) : null}
</section>
);
}
The documentation includes the canonical file at build time. Your application owns the copied source and does not receive automatic updates. Review future changes deliberately and validate it in your application before adoption. Return to the Blocks catalog to compare another pattern.
Install by copying sourceLink to section
- Copy the complete
billing-overviewdirectory into your application-owned Blocks path. - Configure the public PyColors UI package and tokens through the UI installation guide.
- Supply billing facts and actions from your own application state.
- Run lint, type-check, tests and build, then review narrow widths, long values, both themes and keyboard behavior.
"use client";
import { BillingOverviewPanel } from "./blocks/billing-overview";
export function BillingSummary() {
return (
<BillingOverviewPanel
title="Billing"
description="Example values supplied by your application."
planLabel="Plan"
planValue="Growth"
billingLabel="Billing"
billingValue="Monthly"
statusLabel="Status"
statusValue="Active"
renewalLabel="Renews"
renewalValue="October 15"
paymentLabel="Payment method"
paymentValue="Visa ending in 4242"
primaryAction={
<button type="button" onClick={() => undefined}>
Manage billing
</button>
}
/>
);
}The example action is intentionally local. Replace it with your own route or server-backed billing flow only after validating permissions and current billing state.
Consumer-owned contractLink to section
title, planLabel and planValue are required. Description, billing, status,
renewal and payment pairs are optional. Provide both the label and value for an
optional detail when you want it rendered.
primaryAction and secondaryAction are React nodes supplied unchanged by the
consumer. The Block does not infer whether a user may change plans, cancel,
update payment details or open a billing portal. Authorization remains outside
the presentation layer.
Responsive and accessibility notesLink to section
The summary uses a labelled section, semantic definition-list markup and a
responsive two-column details grid. Long values wrap instead of forcing page
width. Preserve meaningful action names, visible focus and native disabled
semantics in controls you supply.
Ownership and boundariesLink to section
Your application owns billing data, pricing truth, subscription state, Stripe or other provider integration, permissions, mutations, redirects and error handling. The Block does not include checkout, Customer Portal, webhooks, persistence, entitlements, authentication, analytics, Registry or CLI behavior.
Explore the Blocks catalog, compare Pricing plans, or compare Starters for a complete application foundation.