Your last renewal did not go through, so the workspace is read only until a payment lands. Everything inside is untouched and waiting.
Unpaid invoice
What stays safe meanwhile
Billing lockout page: an accent card chip and headline with an update-payment seal button on the left, an unpaid invoice table and a square-bullet list of what stays untouched on the right.
The screen a workspace shows after a failed renewal: an accent card chip and headline with an update-payment button on the left, the unpaid invoice as a table and a square-bullet list of what stays untouched on the right.
Upgrade to Pro
Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.
Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.
Radix flavor
npx shadcn add "https://ui.beste.co/r/error26?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://ui.beste.co/r-base/error26?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/error26.tsx, plus the two design-system primitives it renders through: badge6 for the square eyebrow and button1 for the seal call to action.
The installed file exports error26Demo alongside the block: the exact props behind the preview above. Spread it to get a working lockout page in one line.
import { Error26, error26Demo } from "@/components/beste/block/error26";
export default function Billing() {
return <Error26 {...error26Demo} />;
}Then fill the invoice rows from your billing provider. Amounts are plain strings, so currency formatting stays yours:
import { Error26 } from "@/components/beste/block/error26";
export default function Billing({ invoice }: { invoice: { total: string; card: string } }) {
return (
<Error26
label="Payment Required"
code="402"
heading="The card said no, <strong>so the door closed</strong>."
description="Your last renewal did not go through, so the workspace is read only."
labels={{ invoiceTitle: "Unpaid invoice", keptTitle: "What stays safe meanwhile" }}
invoice={[
{ title: "Amount due", value: invoice.total },
{ title: "Card", value: invoice.card },
]}
kept={["Every project, file and comment stays exactly as it is"]}
button={{ label: "Update payment", href: "/billing" }}
link={{ label: "Write to billing", href: "mailto:[email protected]" }}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
label | string | – | Eyebrow text rendered through the square-marker badge |
code | string | – | Status code shown after the eyebrow divider |
heading | string | – | Headline HTML, rendered as an h1; <strong> marks the accent clause |
description | string | – | Explanatory paragraph under the headline |
labels | Error26Labels | {} | Captions above the invoice table and the reassurance list |
invoice | InvoiceRow[] | [] | Rows of the unpaid invoice |
kept | string[] | [] | Square-bullet list of what is preserved during the lockout |
button | ActionLink | – | Seal call to action under the description |
link | ActionLink | – | Text link beside the call to action |
className | string | – | Extra classes for the outer <section> |
type Error26Labels = {
invoiceTitle?: string;
keptTitle?: string;
};
type InvoiceRow = {
title: string;
value: string;
};
type ActionLink = {
label: string;
href: string;
};dl with dt/dd pairs separated by divide-y, so the label and value relationship survives for screen readers instead of reading as two loose columns.lg breakpoint, where the message and the billing panel split into two columns.