BigBlocks Docs
Components/Wallet

DonateButton

Accept Bitcoin donations with customizable preset amounts, QR codes, and a beautiful donation interface

Accept Bitcoin donations with customizable preset amounts and a beautiful UI. The DonateButton component provides a complete donation interface with preset amounts, custom amount input, QR code generation, and seamless Bitcoin transaction handling.

View Component Preview →

Installation

npx bigblocks add donate-button

Import

import { DonateButton } from 'bigblocks';
// or
import { DonateButton, QuickDonateButton } from 'bigblocks';

Props

PropTypeRequiredDefaultDescription
donationAddressstringNo'1BitcoinAuthUi1111111111111111112345'Bitcoin address to receive donations
defaultAmountsnumber[]No[1000000, 5000000, 10000000, 50000000, 100000000]Preset donation amounts in satoshis
customAmountEnabledbooleanNotrueAllow users to enter custom amounts
variant'solid' | 'soft' | 'outline' | 'ghost'No'solid'Button visual style
size'1' | '2' | '3' | '4'No'2'Button size
buttonTextstringNo'Donate'Text displayed on the button
dialogTitlestringNo'Make a Donation'Title shown in the donation dialog
descriptionstringNo-Optional description text
onDonate(amount: number, txid: string) => voidNo-Callback when donation succeeds
onError(error: Error) => voidNo-Callback when donation fails
showQRbooleanNotrueShow QR code for mobile wallets
showCopyAddressbooleanNotrueShow copy address button
disabledbooleanNofalseDisable the donation button

Basic Usage

import { DonateButton } from 'bigblocks';

export default function SupportSection() {
  return (
    <DonateButton
      donationAddress="1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"
      onDonate={(amount, txid) => {
        console.log(`Received ${amount} satoshis! TX: ${txid}`);
      }}
    />
  );
}

Advanced Usage

Custom Amounts and Configuration

import { DonateButton } from 'bigblocks';

export default function CustomDonations() {
  return (
    <DonateButton
      donationAddress="1YourAddress..."
      defaultAmounts={[500000, 1000000, 5000000, 10000000]} // 0.005, 0.01, 0.05, 0.1 BSV
      customAmountEnabled={true}
      buttonText="Support This Project"
      dialogTitle="Support Development"
      description="Your donations help fund ongoing development and server costs."
      variant="solid"
      size="3"
      onDonate={(amount, txid) => {
        // Track donation analytics
        analytics.track('donation_completed', {
          amount_satoshis: amount,
          amount_bsv: amount / 100000000,
          txid
        });
        
        // Show success message
        toast.success(`Thank you for donating ${amount / 100000000} BSV!`);
      }}
      onError={(error) => {
        console.error('Donation failed:', error);
        toast.error('Donation failed. Please try again.');
      }}
    />
  );
}

Support Page Example

import { DonateButton } from 'bigblocks';

export default function SupportPage() {
  const projectAddress = "1YourProjectAddress...";
  
  return (
    <div className="max-w-2xl mx-auto p-8 space-y-6">
      <div className="text-center">
        <h1 className="text-3xl font-bold mb-4">Support Our Work</h1>
        <p className="text-lg text-gray-600 mb-6">
          Your donations help keep this project running and support ongoing development.
        </p>
      </div>
      
      <div className="bg-gray-50 rounded-lg p-6">
        <h2 className="text-xl font-semibold mb-4">Make a Donation</h2>
        <DonateButton
          donationAddress={projectAddress}
          defaultAmounts={[1000000, 5000000, 10000000, 50000000]} // 0.01, 0.05, 0.1, 0.5 BSV
          customAmountEnabled={true}
          buttonText="Donate Bitcoin"
          dialogTitle="Support Development"
          description="All donations go directly to development costs and server infrastructure."
          showQR={true}
          showCopyAddress={true}
          onDonate={(amount, txid) => {
            // Log donation
            console.log('Donation received:', {
              amount_satoshis: amount,
              amount_bsv: amount / 100000000,
              txid,
              timestamp: Date.now()
            });
            
            // Show gratitude
            toast.success('Thank you for your generous support!');
            
            // Optional: redirect to thank you page
            setTimeout(() => {
              router.push('/thank-you');
            }, 2000);
          }}
        />
      </div>
      
      <div className="text-sm text-gray-500 text-center">
        <p>All donations are processed on the Bitcoin SV blockchain.</p>
        <p>Transaction fees are minimal (~$0.001 USD).</p>
      </div>
    </div>
  );
}

QuickDonateButton

For simpler use cases, use the QuickDonateButton component with a preset amount:

import { QuickDonateButton } from 'bigblocks';

export default function ArticleDonation() {
  return (
    <div className="flex items-center space-x-4">
      <p>Enjoyed this article?</p>
      <QuickDonateButton
        donationAddress="1AuthorAddress..."
        amount={1000000} // 0.01 BSV
        buttonText="Tip 0.01 BSV"
        size="1"
        variant="outline"
        onDonate={(amount, txid) => {
          toast.success('Thanks for the tip!');
        }}
      />
    </div>
  );
}

Common Patterns

Donation Goals and Progress

import { DonateButton } from 'bigblocks';
import { useState, useEffect } from 'react';

export default function DonationGoal() {
  const [raised, setRaised] = useState(0);
  const goal = 100000000; // 1 BSV goal
  const progress = (raised / goal) * 100;

  return (
    <div className="space-y-4">
      <div>
        <div className="flex justify-between text-sm mb-2">
          <span>Progress</span>
          <span>{(raised / 100000000).toFixed(4)} BSV / {(goal / 100000000)} BSV</span>
        </div>
        <div className="w-full bg-gray-200 rounded-full h-2">
          <div 
            className="bg-orange-500 h-2 rounded-full transition-all duration-300"
            style={{ width: `${Math.min(progress, 100)}%` }}
          />
        </div>
        <p className="text-xs text-gray-500 mt-1">{progress.toFixed(1)}% funded</p>
      </div>
      
      <DonateButton
        donationAddress="1FundraisingAddress..."
        onDonate={(amount, txid) => {
          // Update progress
          setRaised(prev => prev + amount);
          
          // Check if goal reached
          if (raised + amount >= goal) {
            toast.success('🎉 Fundraising goal reached! Thank you!');
          } else {
            toast.success('Thank you for your donation!');
          }
        }}
      />
    </div>
  );
}

Multiple Donation Categories

import { DonateButton } from 'bigblocks';

export default function DonationCategories() {
  const categories = [
    {
      id: 'development',
      title: 'Development',
      description: 'Support ongoing development and new features',
      address: '1DevAddress...',
      color: 'blue'
    },
    {
      id: 'infrastructure',
      title: 'Infrastructure',
      description: 'Help cover server and hosting costs',
      address: '1InfraAddress...',
      color: 'green'
    },
    {
      id: 'community',
      title: 'Community',
      description: 'Support community events and outreach',
      address: '1CommunityAddress...',
      color: 'purple'
    }
  ];

  return (
    <div className="grid md:grid-cols-3 gap-6">
      {categories.map(category => (
        <div key={category.id} className="border rounded-lg p-6">
          <h3 className="text-lg font-semibold mb-2">{category.title}</h3>
          <p className="text-gray-600 mb-4">{category.description}</p>
          
          <DonateButton
            donationAddress={category.address}
            buttonText={`Support ${category.title}`}
            dialogTitle={`Support ${category.title}`}
            description={category.description}
            size="2"
            onDonate={(amount, txid) => {
              analytics.track('category_donation', {
                category: category.id,
                amount,
                txid
              });
              toast.success(`Thank you for supporting ${category.title}!`);
            }}
          />
        </div>
      ))}
    </div>
  );
}

Styling Variants

import { DonateButton } from 'bigblocks';

export default function StylingExamples() {
  return (
    <div className="space-y-4">
      {/* Solid (default) */}
      <DonateButton variant="solid" size="2" buttonText="Solid Donate" />
      
      {/* Soft */}
      <DonateButton variant="soft" size="2" buttonText="Soft Donate" />
      
      {/* Outline */}
      <DonateButton variant="outline" size="2" buttonText="Outline Donate" />
      
      {/* Ghost */}
      <DonateButton variant="ghost" size="2" buttonText="Ghost Donate" />
      
      {/* Different sizes */}
      <div className="flex items-center space-x-2">
        <DonateButton size="1" buttonText="Small" />
        <DonateButton size="2" buttonText="Medium" />
        <DonateButton size="3" buttonText="Large" />
        <DonateButton size="4" buttonText="Extra Large" />
      </div>
    </div>
  );
}

Authentication Requirements

The DonateButton component requires Bitcoin authentication to function. Wrap your app with the required providers:

import { BitcoinAuthProvider, BitcoinQueryProvider } from 'bigblocks';

function App() {
  return (
    <BitcoinQueryProvider>
      <BitcoinAuthProvider config={{ apiUrl: '/api' }}>
        <YourAppWithDonateButtons />
      </BitcoinAuthProvider>
    </BitcoinQueryProvider>
  );
}

Backend Integration

API Requirements

The component uses the useSendBSV hook which requires these API endpoints:

// POST /api/wallet/send
{
  "recipientAddress": "1RecipientAddress...",
  "amount": 1000000, // satoshis
  "message": "Donation" // optional
}

// Response:
{
  "success": true,
  "txid": "abc123...",
  "fee": 500 // transaction fee in satoshis
}

Donation Tracking

// Optional: Track donations in your database
CREATE TABLE donations (
  id UUID PRIMARY KEY,
  txid VARCHAR(64) UNIQUE NOT NULL,
  donor_address VARCHAR(64) NOT NULL,
  recipient_address VARCHAR(64) NOT NULL,
  amount BIGINT NOT NULL,
  message TEXT,
  category VARCHAR(50),
  timestamp TIMESTAMP DEFAULT NOW(),
  confirmed BOOLEAN DEFAULT FALSE
);

Troubleshooting

Common Issues

"Insufficient funds" error

  • Ensure the user has enough BSV balance
  • Check for minimum transaction amount requirements
  • Verify fee calculation includes transaction costs

QR code not displaying

  • Ensure showQR prop is set to true
  • Check that the donation address is valid
  • Verify mobile wallet compatibility

Transaction fails to broadcast

  • Check API endpoint authentication
  • Verify the recipient address is valid
  • Ensure the transaction is properly signed

Error Handling

<DonateButton
  donationAddress="1YourAddress..."
  onError={(error) => {
    switch (error.message) {
      case 'INSUFFICIENT_FUNDS':
        toast.error('Insufficient BSV balance for this donation');
        break;
      case 'INVALID_ADDRESS':
        toast.error('Invalid donation address');
        break;
      case 'NETWORK_ERROR':
        toast.error('Network error. Please try again.');
        break;
      default:
        toast.error('Donation failed. Please try again.');
    }
  }}
/>

Security Considerations

  • Address Validation: Always validate donation addresses
  • Amount Limits: Consider setting maximum donation amounts
  • Rate Limiting: Implement rate limiting on donation endpoints
  • Audit Trail: Log all donation attempts for security review

API Reference

Default Amounts

The default preset amounts are:

  • 0.01 BSV (1,000,000 satoshis)
  • 0.05 BSV (5,000,000 satoshis)
  • 0.1 BSV (10,000,000 satoshis)
  • 0.5 BSV (50,000,000 satoshis)
  • 1 BSV (100,000,000 satoshis)

QR Code Format

The QR code includes:

bitcoin:{address}?amount={amount_in_bsv}&message={message}

Dependencies

  • useBitcoinAuth - Authentication hook
  • useSendBSV - Transaction sending hook
  • QRCodeRenderer - QR code display
  • Radix UI components for dialogs and buttons