@blocklet/payment-react
Version:
Reusable react components for payment kit v2
140 lines (120 loc) • 6.6 kB
Markdown
# PricingTable
The `PricingTable` component is a flexible UI element designed to display subscription plans and pricing options in a structured, responsive table. It allows users to toggle between billing cycles (e.g., monthly, yearly), select their preferred currency, and choose a plan to proceed with.
This component is ideal for building custom checkout flows where you need granular control over the presentation of pricing plans. For a more integrated solution that handles the entire checkout process, consider using the higher-level [`CheckoutTable`](./components-checkout-checkout-table.md) component.
## Props
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `table` | `TPricingTableExpanded` | - | **Required**. An object containing the pricing table data, including a list of items (plans), currency information, and other details. |
| `onSelect` | `(priceId: string, currencyId: string) => void` | - | **Required**. A callback function that is triggered when a user clicks the action button for a plan. It receives the selected `priceId` and `currencyId`. |
| `alignItems` | `'center' \| 'left'` | `'center'` | Controls the horizontal alignment of the table's header content (billing cycle and currency selectors). |
| `mode` | `'checkout' \| 'select'` | `'checkout'` | Determines the behavior and text of the action button. `'checkout'` mode is for initiating a payment, while `'select'` mode is for selecting a plan within a larger form. |
| `interval` | `string` | `''` | Sets the initially selected billing interval. The format is typically `interval-interval_count` (e.g., `month-1`, `year-1`). |
| `hideCurrency` | `boolean` | `false` | If `true`, the currency selector dropdown will be hidden, even if multiple currencies are available. |
## Usage Example
To use the `PricingTable`, you must wrap it in a `PaymentProvider`. The component requires a `table` object with your product data and an `onSelect` handler to manage user selections.
```tsx Integration Example icon=lucide:code
import { PaymentProvider } from '@blocklet/payment-react';
import { PricingTable } from '@blocklet/payment-react/components/ui';
import type { TPricingTableExpanded } from '@blocklet/payment-types';
// In a real application, you would fetch this data from your payment service.
const pricingTableData: TPricingTableExpanded = {
id: 'pt_123',
livemode: false,
currency: { id: 'usd', symbol: '$' },
items: [
{
price_id: 'price_basic_monthly',
product: {
name: 'Basic Plan',
description: 'For individuals and small teams.',
unit_label: 'user',
features: [{ name: '5 Projects' }, { name: '10GB Storage' }, { name: 'Basic Support' }],
},
price: {
currency: 'usd',
unit_amount: '1000', // in cents
recurring: { interval: 'month', interval_count: 1 },
currency_options: [{ currency_id: 'usd', unit_amount: '1000' }],
},
is_highlight: false,
},
{
price_id: 'price_pro_monthly',
product: {
name: 'Pro Plan',
description: 'For growing businesses.',
unit_label: 'user',
features: [{ name: 'Unlimited Projects' }, { name: '100GB Storage' }, { name: 'Priority Support' }],
},
price: {
currency: 'usd',
unit_amount: '2500',
recurring: { interval: 'month', interval_count: 1 },
currency_options: [{ currency_id: 'usd', unit_amount: '2500' }],
},
is_highlight: true,
highlight_text: 'Popular',
},
{
price_id: 'price_basic_yearly',
product: {
name: 'Basic Plan',
description: 'For individuals and small teams.',
unit_label: 'user',
features: [{ name: '5 Projects' }, { name: '10GB Storage' }, { name: 'Basic Support' }],
},
price: {
currency: 'usd',
unit_amount: '10000',
recurring: { interval: 'year', interval_count: 1 },
currency_options: [{ currency_id: 'usd', unit_amount: '10000' }],
},
is_highlight: false,
},
{
price_id: 'price_pro_yearly',
product: {
name: 'Pro Plan',
description: 'For growing businesses.',
unit_label: 'user',
features: [{ name: 'Unlimited Projects' }, { name: '100GB Storage' }, { name: 'Priority Support' }],
},
price: {
currency: 'usd',
unit_amount: '25000',
recurring: { interval: 'year', interval_count: 1 },
currency_options: [{ currency_id: 'usd', unit_amount: '25000' }],
},
is_highlight: true,
highlight_text: 'Popular',
},
],
};
function MyPricingPage() {
const { session, connect } = useSessionContext();
const handlePlanSelect = async (priceId: string, currencyId: string) => {
console.log(`Plan selected: ${priceId}, Currency: ${currencyId}`);
// Here, you would typically navigate to a checkout page or open a payment modal.
// For example: `router.push(\"/checkout?price_id=${priceId}¤cy_id=${currencyId}\")`
alert(`Selected Price ID: ${priceId}`);
};
return (
<PaymentProvider session={session} connect={connect}>
<div style={{ maxWidth: 800, margin: 'auto' }}>
<PricingTable table={pricingTableData} onSelect={handlePlanSelect} />
</div>
</PaymentProvider>
);
}
export default MyPricingPage;
```
## Usage Scenarios
### Mode: `checkout` vs. `select`
The `mode` prop changes the call-to-action button to fit different use cases.
- **`mode='checkout'` (Default):** The button text will be context-aware, showing labels like "Subscribe" or "Start Trial". This mode is intended for when the user's click should immediately initiate the payment or checkout process.
- **`mode='select'`:** The button text will show "Select" or "Selected". This is useful when the pricing table is part of a larger form or multi-step process. The `onSelect` callback can be used to update the application's state with the chosen plan, and the UI will visually indicate which plan is currently selected.
### Handling `onSelect`
The `onSelect` callback is the core mechanism for handling user interaction. It's an async function that receives the `priceId` and `currencyId` of the chosen plan. Your application logic should reside here. Common actions include:
- Storing the selected plan in your application's state.
- Redirecting the user to a dedicated checkout page, passing the `priceId` as a URL parameter.
- Using the `priceId` to create a checkout session with the payment service backend and then opening a payment form.