Payment Failure
A payment failure card that explains why a payment could not be processed, with actions to retry, go home, or contact support.
Common reasons for payment failure:
- Insufficient funds in your account
- Incorrect card details or expired card
- Card declined by your bank
- Network connection issues
Please check your payment details and try again, or contact your bank for more information.
"use client";
import React, { useState } from "react";
import { useRouter } from "next/navigation";
import { PaymentFailure } from "@/registry/billingsdk/payment-failure";
export function PaymentFailureDemo() {
const [isRetrying, setIsRetrying] = useState(false);
const router = useRouter();
const handleRetry = async () => {
setIsRetrying(true);
try {
// TODO: your actual retry logic (redirect to payment, call API, etc.)
await new Promise((resolve) => setTimeout(resolve, 1500));
// e.g. router.push("/checkout");
} finally {
setIsRetrying(false);
}
};
return (
<div className="bg-background flex min-h-screen items-center justify-center p-4">
<PaymentFailure
isRetrying={isRetrying}
onRetry={handleRetry}
onSecondary={() => router.push("/")}
onTertiary={() => router.push("/support")}
reasons={[
"Insufficient funds in your account",
"Incorrect card details or expired card",
"Card declined by your bank",
"Network connection issues",
]}
// Optional overrides:
// title="Payment declined"
// subtitle="Your bank declined the transaction."
// retryButtonText="Retry Payment"
// secondaryButtonText="Go Home"
// tertiaryButtonText="Contact Support"
/>
</div>
);
}Installation
bash npx shadcn@latest add @billingsdk/payment-failure
bash pnpm dlx shadcn@latest add @billingsdk/payment-failure
bash yarn dlx shadcn@latest add @billingsdk/payment-failure
bash bunx shadcn@latest add @billingsdk/payment-failure
bash npx @billingsdk/cli add payment-failure bash pnpm dlx @billingsdk/cli add payment-failure
bash yarn dlx @billingsdk/cli add payment-failure
bash bunx @billingsdk/cli add payment-failure
Usage
import { PaymentFailure } from "@/components/billingsdk/payment-failure";// Controlled usage (recommended)
const [isRetrying, setIsRetrying] = useState(false);
async function handleRetry() {
setIsRetrying(true);
// Add your retry logic here (e.g., redirect to checkout or re-initiate payment)
await new Promise((resolve) => setTimeout(resolve, 1500));
setIsRetrying(false);
}
<PaymentFailure
isRetrying={isRetrying}
onRetry={handleRetry}
onSecondary={() => router.push("/")}
onTertiary={() => router.push("/support")}
/>;Customizing text
<PaymentFailure
title="Transaction Declined"
subtitle="Your bank rejected the payment."
message="Please try again or use a different payment method."
retryButtonText="Retry Payment"
secondaryButtonText="Go Home"
tertiaryButtonText="Contact Support"
onRetry={() => console.log("retry")}
onSecondary={() => router.push("/")}
onTertiary={() => router.push("/support")}
/>Props
| Prop | Type | Required | Description |
|---|---|---|---|
title | string | ❌ | Optional heading (default: "Payment Failed") |
subtitle | string | ❌ | Optional subtext (default: "We couldn't process your payment.") |
message | string | ❌ | Additional explanatory message displayed under the reasons list |
reasons | string[] | ❌ | List of possible failure reasons (defaults to common payment failure causes) |
isRetrying | boolean | ❌ | Shows loading state and disables retry button |
retryButtonText | string | ❌ | Primary action label (default: "Try Again") |
secondaryButtonText | string | ❌ | Secondary button label (default: "Home") |
tertiaryButtonText | string | ❌ | Tertiary button label (default: "Support") |
onRetry | () => void | ❌ | Callback fired when user presses retry |
onSecondary | () => void | ❌ | Callback fired when user presses the secondary action |
onTertiary | () => void | ❌ | Callback fired when user presses tertiary action |
className | string | ❌ | Additional classes for styling / layout |
Theming
This dialog inherits BillingSDK theme tokens via getThemeStyles, remaining consistent with other components. Colors adapt to light/dark modes and active theme.
Example
"use client";
import React, { useState } from "react";
import { useRouter } from "next/navigation";
import { PaymentFailure } from "@/registry/billingsdk/payment-failure";
export function PaymentFailureDemo() {
const [isRetrying, setIsRetrying] = useState(false);
const router = useRouter();
const handleRetry = async () => {
setIsRetrying(true);
try {
// TODO: your actual retry logic (redirect to payment, call API, etc.)
await new Promise((resolve) => setTimeout(resolve, 1500));
// e.g. router.push("/checkout");
} finally {
setIsRetrying(false);
}
};
return (
<div className="bg-background flex min-h-screen items-center justify-center p-4">
<PaymentFailure
isRetrying={isRetrying}
onRetry={handleRetry}
onSecondary={() => router.push("/")}
onTertiary={() => router.push("/support")}
reasons={[
"Insufficient funds in your account",
"Incorrect card details or expired card",
"Card declined by your bank",
"Network connection issues",
]}
// Optional overrides:
// title="Payment declined"
// subtitle="Your bank declined the transaction."
// retryButtonText="Retry Payment"
// secondaryButtonText="Go Home"
// tertiaryButtonText="Contact Support"
/>
</div>
);
}