@volr/react-ui
v0.3.0
Published
Volr React UI - UI components for Volr built on top of @volr/react
Maintainers
Readme
@volr/react-ui
Pre-built UI components for Volr Payment Gateway, built on top of @volr/react and @volr/sdk-core, with minimal, modern design.
Installation
npm i @volr/react-ui
# or
yarn add @volr/react-uiQuick Start
1. Wrap your app with VolrUIProvider
import { VolrUIProvider } from '@volr/react-ui';
import type { VolrUIConfig } from '@volr/react-ui';
const volrConfig: VolrUIConfig = {
projectApiKey: 'your-project-api-key',
appName: 'My App',
accentColor: '#3b82f6',
enabledLoginMethods: ['email', 'social'],
socialProviders: ['google', 'twitter'],
};
function App() {
return (
<VolrUIProvider config={volrConfig}>
<YourApp />
</VolrUIProvider>
);
}Payment Integration
Volr provides a simple, Stripe-like payment experience for Web3 applications.
Basic Payment
import { useVolrPay } from '@volr/react-ui';
// Or from @volr/react if not using UI components
function CheckoutButton() {
const { pay } = useVolrPay();
const handleCheckout = async () => {
const payment = await pay({
amount: 9.99,
item: {
name: 'Premium Plan',
description: 'Monthly subscription',
},
handlers: {
onSuccess: (result) => {
console.log('Payment confirmed!', result.txHash);
},
onError: (error) => {
console.error('Payment failed:', error.message);
},
},
});
// Optionally wait for confirmation
const result = await payment.wait();
};
return <button onClick={handleCheckout}>Subscribe $9.99</button>;
}External Wallet Payments (Optional)
Enable external wallet payments inside PaymentModal:
const volrConfig: VolrUIConfig = {
projectApiKey: 'your-project-api-key',
appName: 'My App',
allowExternalWalletPayment: true,
walletPolicy: { requireVolrWalletOnLogin: false },
};Notes:
- External wallet payments are only shown for ERC-20 tokens with permit support.
- When
walletPolicy.requireVolrWalletOnLoginis true, external wallet payment is disabled.
Payment with Reference ID
Track payments with your own order ID:
const payment = await pay({
amount: 29.99,
item: { name: 'Pro License' },
referenceId: 'order_12345', // Your order ID
metadata: {
userId: 'user_abc',
plan: 'pro',
},
});Idempotent Payments
Prevent duplicate payments with idempotency key:
const payment = await pay({
amount: 49.99,
item: { name: 'Enterprise License' },
idempotencyKey: `order_${orderId}_${userId}`, // Unique per payment intent
});Check Payment Status
import { useVolrPay } from '@volr/react-ui';
function OrderStatus({ paymentId }: { paymentId: string }) {
const { checkPayment } = useVolrPay();
const [status, setStatus] = useState<string>('loading');
useEffect(() => {
checkPayment(paymentId).then((result) => {
setStatus(result.status); // 'CONFIRMED' | 'PENDING' | 'FAILED' | ...
});
}, [paymentId]);
return <div>Payment Status: {status}</div>;
}Payment History
import { useVolrPay } from '@volr/react-ui';
function PaymentHistory() {
const { getPaymentHistory } = useVolrPay();
const [payments, setPayments] = useState([]);
useEffect(() => {
getPaymentHistory({ take: 10 }).then((result) => {
setPayments(result.payments);
});
}, []);
return (
<ul>
{payments.map((p) => (
<li key={p.id}>
{p.itemName} - {p.amount} {p.token.symbol} - {p.status}
</li>
))}
</ul>
);
}PayOptions Reference
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| amount | number | ✅ | Amount in token units (before decimals) |
| item.name | string | ❌ | Item name displayed in modal |
| item.description | string | ❌ | Item description |
| item.image | string | ❌ | Item image URL (falls back to project logo) |
| referenceId | string | ❌ | Your order/reference ID |
| metadata | Record<string, string> | ❌ | Custom metadata (max 50 keys) |
| idempotencyKey | string | ❌ | Unique key to prevent duplicates |
| expiresInSec | number | ❌ | Expiration time (default: 900 = 15 min) |
| handlers.onCreated | (payment) => void | ❌ | Called when payment is created |
| handlers.onProcessing | (payment) => void | ❌ | Called when transaction is broadcasted |
| handlers.onSuccess | (result) => void | ❌ | Called when payment is confirmed |
| handlers.onError | (error) => void | ❌ | Called on error |
| handlers.onCancel | () => void | ❌ | Called when user cancels |
Payment Modal Flow
- Payment Info - Shows item details, amount, and user's balance
- Processing - Passkey signing → Transaction broadcast → On-chain confirmation
- Result - Success or failure with retry option
Account & Authentication
Login / Account Modal
import { useVolrModal, useVolr } from '@volr/react-ui';
function AuthButton() {
const { open } = useVolrModal();
const { evm, isLoggedIn, logout } = useVolr();
return (
<div>
{isLoggedIn ? (
<>
<p>Wallet: {evm.address}</p>
<button onClick={() => open({ mode: 'account' })}>My Account</button>
<button onClick={logout}>Logout</button>
</>
) : (
<button onClick={() => open()}>Login</button>
)}
</div>
);
}Deposit Modal
Open deposit modal to let users top up their wallet:
import { useVolrModal } from '@volr/react-ui';
function DepositButton() {
const { open } = useVolrModal();
return (
<button onClick={() => open({ mode: 'deposit' })}>
Deposit
</button>
);
}
// With specific asset pre-selected
<button onClick={() => open({ mode: 'deposit', asset: { chainId: 8453, symbol: 'USDC' } })}>
Deposit USDC
</button>Configuration
VolrUIProvider Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| config.projectApiKey | string | Required | Project API key |
| config.appName | string | Required | Application name |
| config.accentColor | string | '#303030' | Accent color for buttons |
| config.enabledLoginMethods | ('email' \| 'social' \| 'siwe')[] | ['email', 'social', 'siwe'] | Login methods |
| config.socialProviders | ('google' \| 'twitter')[] | ['google', 'twitter'] | Social providers |
| config.keyStorageType | 'passkey' \| 'mpc' | 'passkey' | Key storage type |
| config.branding | BrandingConfig | undefined | Custom branding |
Note: Payment token and deposit assets are configured via the Volr Dashboard.
API Reference
useVolrPay
Hook for payment operations with PaymentModal integration.
import { useVolrPay } from '@volr/react-ui';
const {
pay, // (options: PayOptions) => Promise<PaymentHandle>
checkPayment, // (id: string) => Promise<PaymentResult>
getPaymentHistory, // (options?) => Promise<{ payments, total }>
isPaymentInProgress // boolean
} = useVolrPay();
// PaymentHandle returned from pay()
interface PaymentHandle {
id: string;
status: PaymentStatus;
wait: () => Promise<PaymentResult>; // Wait for completion
cancel: () => Promise<void>; // Cancel (PENDING only)
}useVolrPaymentApi (Advanced)
Headless payment API for advanced use cases (no UI).
import { useVolrPaymentApi } from '@volr/react-ui';
const {
createPayment, // (options: PayOptions) => Promise<PaymentResult>
checkPayment, // (id: string) => Promise<PaymentResult>
getPaymentHistory, // (options?) => Promise<{ payments, total }>
updatePaymentToProcessing,// (id, txId) => Promise<PaymentResult>
cancelPayment, // (id) => Promise<PaymentResult>
pollPaymentStatus, // (id) => Promise<PaymentResult>
isLoading, // boolean
} = useVolrPaymentApi();useVolrModal
Hook for controlling modals.
import { useVolrModal } from '@volr/react-ui';
const { isOpen, mode, open, close } = useVolrModal();
open(); // Account modal (login or account info)
open({ mode: 'account' }); // Same as above
open({ mode: 'deposit' }); // Deposit modal
open({ mode: 'deposit', asset: {...} }); // Deposit with specific asset
open({ mode: 'payment', payment: {...} }); // Payment modal (internal)
close();useVolr
Hook for wallet and user state.
import { useVolr } from '@volr/react-ui';
const {
evm, // EvmNamespace (see below)
evmAddress, // `0x${string}` | undefined (deprecated, use evm.address)
email, // string | undefined
isLoggedIn, // boolean
signerType, // 'passkey' | 'external_wallet' | 'mpc' | undefined
logout, // () => Promise<void>
isLoading, // boolean
error, // Error | null
} = useVolr();Sign Request Confirmation
When using @volr/react-ui, signing operations (signMessage, signTypedData) automatically show a confirmation modal before signing. This protects users from signing malicious messages without their knowledge.
import { useVolr } from '@volr/react-ui';
function SignButton() {
const { evm } = useVolr();
const handleSign = async () => {
// Modal automatically appears showing the message content
// User must click "Sign" to proceed
const signature = await evm.signMessage('Hello, World!');
console.log('Signed:', signature);
};
return <button onClick={handleSign}>Sign Message</button>;
}The modal displays:
- For
signMessage: The original message content (string or hex) - For
signTypedData: Domain info and message fields in a readable format
Advanced: Web3 Transactions
For advanced use cases beyond payments, you can send arbitrary transactions.
EvmNamespace & EvmChainClient
import { useVolr } from '@volr/react-ui';
function SendToken() {
const { evm } = useVolr();
const handleSend = async () => {
// Chain-agnostic: Wallet address
const address = evm.address;
// Chain-agnostic: Sign a message (shows confirmation modal)
const signature = await evm.signMessage('Hello');
// Chain-specific: Get client for Base
const client = evm.client(8453);
// Read contract
const balance = await client.readContract({
address: tokenAddress,
abi: erc20Abi,
functionName: 'balanceOf',
args: [address],
});
// Send transaction
const result = await client.sendTransaction({
to: '0x...',
data: '0x...',
value: 0n,
});
// Send batch
const result = await client.sendBatch([
{
target: tokenAddress,
abi: erc20Abi,
functionName: 'transfer',
args: [recipient, amount],
gasLimit: 100000n,
},
]);
};
}Login Flows
Email Login
- Enter email → Receive 6-digit code → Enter code → Passkey setup (new users)
Social Login (Google, Twitter)
- Click social button → OAuth redirect → Authorize → Passkey setup (new users)
Wallet Login (SIWE)
- Click Wallet Login → Connect wallet → Sign message → Passkey setup (new users)
Examples
Email Only Config
const volrConfig: VolrUIConfig = {
projectApiKey: 'your-api-key',
appName: 'My App',
enabledLoginMethods: ['email'],
};Social Only Config
const volrConfig: VolrUIConfig = {
projectApiKey: 'your-api-key',
appName: 'My App',
enabledLoginMethods: ['social'],
socialProviders: ['google'],
};License
MIT
