React paywall — Custom UI
Override class names, disable default styles, or replace the locked overlay with your own component tree.
Class slots
Use appearance.classNames — keys include gate, overlay, card, btnPrimary, walletPicker, agent, and more. Export defaultPaywallClassNames to extend defaults.
Unstyled mode
<PaywallProvider
appearance={{
unstyled: true,
classNames: {
overlay: "absolute inset-0 flex items-center justify-center bg-black/80",
card: "max-w-md rounded-xl bg-neutral-900 p-8",
btnPrimary: "btn btn-primary w-full",
},
}}
>renderLockedOverlay
Full control of the paywall UI while keeping inspect / pay / wallet logic:
<PaywallGate
resourceUrl={url}
renderLockedOverlay={(s) => (
<div className="my-modal">
<h2>{s.title}</h2>
<p>{s.displayPrice}</p>
{s.error && <p role="alert">{s.error}</p>}
{!s.walletAddress && (
<button onClick={s.onConnect} disabled={s.busy}>Connect</button>
)}
<button onClick={s.onPay} disabled={s.busy}>Pay</button>
{s.showWalletPicker &&
s.pickerWallets.map((w) => (
<button key={w.id} onClick={() => s.onWalletSelect(w.id)}>{w.name}</button>
))}
</div>
)}
/>State type: PaywallLockedOverlayState (exported).
Headless
usePaywall()+PaywallOverlayusePaidFetch(resourceUrl)for custom fetch flows
Appearance provider only
<PaywallAppearanceProvider appearance={{ theme: { accent: "#000" } }}>
<WalletPicker wallets={w} onSelect={…} />
</PaywallAppearanceProvider>See also Theming.