The BasePayButton
is a ready-to-use React component that provides a seamless payment experience using Base Account. It handles the entire payment flow including user interaction, transaction processing, and result handling.
Please Follow the Brand Guidelines
If you intend on using the BasePayButton, please follow the Brand Guidelines to ensure consistency across your application.
Installation
npm install @base-org/account-ui
Basic Usage
import { BasePayButton } from '@base-org/account-ui/react';
function PaymentForm() {
const handlePaymentResult = (result) => {
if (result.success) {
console.log('Payment successful!', result);
} else {
console.error('Payment failed:', result.error);
}
};
return (
<BasePayButton
paymentOptions={{
amount: '10.00',
to: 'your-wallet.eth',
testnet: true
}}
colorScheme="light"
onPaymentResult={handlePaymentResult}
/>
);
}
Props
paymentOptions (required)
Payment configuration object with the following properties:
The payment amount in USDC (e.g., “10.50” for $10.50)
The recipient wallet address or ENS name
Whether to use testnet for the payment (default: false)
Object containing information requests to collect during payment
Styling Props
colorScheme
'light' | 'dark' | 'system'
Color scheme for the button appearance (default: ‘system’)
size
'small' | 'medium' | 'large'
Button size (default: ‘medium’)
Button variant style (default: ‘solid’)
Whether the button is disabled (default: false)
Event Handlers
Callback function called when payment completes (success or failure)
Custom click handler (called before payment processing)
Payment Options
Basic Payment
const paymentOptions = {
amount: '25.00',
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f6E456',
testnet: true
};
<BasePayButton
paymentOptions={paymentOptions}
colorScheme="light"
onPaymentResult={handleResult}
/>
Payment with User Info Collection
const paymentOptions = {
amount: '49.99',
to: 'store.eth',
payerInfo: {
requests: [
{ type: 'email', optional: false },
{ type: 'name', optional: true },
{ type: 'physicalAddress', optional: false }
],
callbackURL: 'https://api.example.com/validate' // Optional
}
};
<BasePayButton
paymentOptions={paymentOptions}
onPaymentResult={(result) => {
if (result.success) {
console.log('Payment successful!');
console.log('User info:', result.payerInfoResponses);
}
}}
/>
Styling Options
Color Schemes
{/* Light theme */}
<BasePayButton
paymentOptions={paymentOptions}
colorScheme="light"
/>
{/* Dark theme */}
<BasePayButton
paymentOptions={paymentOptions}
colorScheme="dark"
/>
{/* System theme (follows user's system preference) */}
<BasePayButton
paymentOptions={paymentOptions}
colorScheme="system"
/>
Sizes and Variants
{/* Different sizes */}
<BasePayButton size="small" paymentOptions={paymentOptions} />
<BasePayButton size="medium" paymentOptions={paymentOptions} />
<BasePayButton size="large" paymentOptions={paymentOptions} />
{/* Different variants */}
<BasePayButton variant="solid" paymentOptions={paymentOptions} />
<BasePayButton variant="outline" paymentOptions={paymentOptions} />
Event Handling
Payment Result Handling
const handlePaymentResult = (result) => {
if (result.success) {
// Payment successful
console.log('Transaction hash:', result.transactionHash);
console.log('Block number:', result.blockNumber);
// Handle user info if collected
if (result.userInfo) {
console.log('User email:', result.userInfo.email);
console.log('User name:', result.userInfo.name);
}
// Update UI, redirect, etc.
showSuccessMessage();
redirectToThankYouPage();
} else {
// Payment failed
console.error('Payment error:', result.error);
// Handle different error types
if (result.error.includes('insufficient funds')) {
showInsufficientFundsMessage();
} else if (result.error.includes('user rejected')) {
showUserCancelledMessage();
} else {
showGenericErrorMessage();
}
}
};
Custom Click Handler
const handleClick = () => {
// Custom logic before payment
console.log('User clicked pay button');
// Analytics tracking
trackEvent('payment_button_clicked', {
amount: '10.00',
product: 'subscription'
});
// Validation
if (!isValidPayment()) {
alert('Please complete the form first');
return false; // Prevent payment
}
return true; // Continue with payment
};
<BasePayButton
paymentOptions={paymentOptions}
onClick={handleClick}
onPaymentResult={handlePaymentResult}
/>
Complete Example
import React, { useState } from 'react';
import { BasePayButton } from '@base-org/account-ui/react';
export default function CheckoutPage() {
const [loading, setLoading] = useState(false);
const [paymentStatus, setPaymentStatus] = useState(null);
const paymentOptions = {
amount: '29.99',
to: 'merchant.eth',
testnet: true,
payerInfo: {
requests: [
{ type: 'email', optional: false },
{ type: 'name', optional: true },
{ type: 'physicalAddress', optional: false }
]
}
};
const handlePaymentResult = (result) => {
setLoading(false);
if (result.success) {
setPaymentStatus({
type: 'success',
message: 'Payment successful!',
transactionHash: result.transactionHash,
userInfo: result.userInfo
});
// Send confirmation email
if (result.userInfo?.email) {
sendConfirmationEmail(result.userInfo.email, result.transactionHash);
}
} else {
setPaymentStatus({
type: 'error',
message: `Payment failed: ${result.error}`
});
}
};
const handleClick = () => {
setLoading(true);
setPaymentStatus(null);
};
return (
<div className="checkout-page">
<h2>Complete Your Purchase</h2>
<div className="product-info">
<h3>Premium Subscription</h3>
<p>$29.99/month</p>
</div>
<BasePayButton
paymentOptions={paymentOptions}
colorScheme="light"
size="large"
disabled={loading}
onClick={handleClick}
onPaymentResult={handlePaymentResult}
/>
{loading && (
<div className="loading">
Processing payment...
</div>
)}
{paymentStatus && (
<div className={`status ${paymentStatus.type}`}>
<p>{paymentStatus.message}</p>
{paymentStatus.transactionHash && (
<p>Transaction: {paymentStatus.transactionHash}</p>
)}
{paymentStatus.userInfo && (
<div>
<p>Email: {paymentStatus.userInfo.email}</p>
{paymentStatus.userInfo.name && (
<p>Name: {paymentStatus.userInfo.name.firstName} {paymentStatus.userInfo.name.lastName}</p>
)}
</div>
)}
</div>
)}
<style jsx>{`
.checkout-page {
max-width: 400px;
margin: 0 auto;
padding: 20px;
}
.product-info {
background: #f5f5f5;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
}
.loading {
text-align: center;
margin-top: 15px;
color: #666;
}
.status {
margin-top: 20px;
padding: 15px;
border-radius: 8px;
}
.status.success {
background: #d4edda;
border: 1px solid #c3e6cb;
color: #155724;
}
.status.error {
background: #f8d7da;
border: 1px solid #f5c6cb;
color: #721c24;
}
`}</style>
</div>
);
}
TypeScript Support
The component is fully typed when using TypeScript:
import { BasePayButton, PaymentOptions, PaymentResult } from '@base-org/account-ui/react';
interface CheckoutProps {
amount: string;
recipient: string;
}
function Checkout({ amount, recipient }: CheckoutProps) {
const paymentOptions: PaymentOptions = {
amount,
to: recipient,
testnet: true
};
const handleResult = (result: PaymentResult) => {
// TypeScript provides full type safety
if (result.success) {
console.log(result.transactionHash); // ✅ Type-safe
}
};
return (
<BasePayButton
paymentOptions={paymentOptions}
onPaymentResult={handleResult}
/>
);
}
Testing
For testing your integration:
- Use testnet mode: Set
testnet: true
in payment options
- Get test USDC: Use Circle’s faucet on Base Sepolia
- Test different scenarios: Try successful payments, cancellations, and errors
- Verify user info collection: Test with different
payerInfo
configurations
The BasePayButton provides a complete, production-ready payment solution that handles all the complexity of crypto payments while providing a familiar user experience.
Responses are generated using AI and may contain mistakes.