Paywall
A feature list and selectable subscription plans with purchase, restore and policy callbacks.
npx @eoria/cli add paywallThe command also adds Alert, Badge, Button, Card, IconButton, RadioGroup and Text.
Usage
import { Paywall } from '@/components/blocks/paywall'
<Paywall title="Make room for more" subtitle="Your favourites, wherever you go." features={[ { title: 'Every collection', description: 'Use all current and future collections.' }, { title: 'Available offline', description: 'Download favourites to take with you.' }, ]} plans={[ { id: 'annual', title: 'Yearly', price: '€39.99', period: 'year', badge: 'Most popular', perMonth: 'About €3.33 per month', description: 'Billed once a year. Cancel anytime.', }, { id: 'monthly', title: 'Monthly', price: '€4.99', period: 'month' }, ]} onSelectPlan={async (planId) => { await purchasePlan(planId) }} onRestore={async () => { await restorePurchases() }} onTerms={() => openTerms()} onPrivacy={() => openPrivacy()} onClose={() => closePaywall()}/>Supply the purchase, restore, policy and close functions from your app.
Props
| Prop | Type | Default |
|---|---|---|
title |
string |
required |
subtitle |
string |
required |
features |
PaywallFeature[] |
required |
plans |
PaywallPlan[] |
required |
ctaLabel |
string |
'Continue' |
onSelectPlan |
(planId: string) => void | Promise<void> |
required |
onRestore |
() => void | Promise<void> |
|
onTerms |
() => void | Promise<void> |
|
onPrivacy |
() => void | Promise<void> |
|
onClose |
() => void | Promise<void> |
|
insetTop |
boolean |
true |
style |
StyleProp<ViewStyle> |
Data types
type PaywallFeature = { icon?: ReactElement<{ size?: number; color?: string }> title: string description?: string}
type PaywallPlan = { id: string title: string price: string period: string badge?: string description?: string perMonth?: string}Notes
- The first plan with a badge starts selected. If no plan has one, the first plan starts selected. Removing the selected plan falls back to that same rule. An empty plan list disables Continue.
- Each Card is one radio option in a RadioGroup. Its label includes the plan title, price, billing period, badge and description. The selected border uses
theme.colors.primaryand a check icon also marks the selection. - Feature icons accept
sizeandcolor, as lucide icons do. Omit an icon to use a check. Each feature title and description read as one element. - The feature and plan rows use a FlatList. The purchase button and policy links stay below it, above the home indicator. Pass
insetTop={false}under a navigation header. - Price, period and
perMonthare display strings. Read localized prices from your billing service and pass them through. The block does not calculate discounts or charge a customer. onSelectPlanreceives only the selected ID. Return your purchase promise to show loading. Every optional action also accepts a promise, and other actions stay blocked until it settles.- Rejections show
error.messagein an Alert with a polite live region. A non-Error rejection uses generic text. State updates stop after unmount, so a successful purchase can navigate away. - Restore, Terms, Privacy and Close only appear when their callbacks are supplied. Keep navigation and billing in those callbacks.
- Change first: the headline, feature copy and Continue label to match what the plan includes.