> ## Documentation Index
> Fetch the complete documentation index at: https://docs.phantom.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Phantom React SDK

> Integrate Phantom wallets into React web apps with hooks for multi-chain transaction support.

The Phantom Connect React SDK provides React hooks for connecting to existing Phantom user wallets in your React apps with native transaction support across multiple blockchains.

### Quick start

Generate a new Solana project using the **Phantom Embedded React Starter** template.

<Tabs>
  <Tab title="npm">
    ```bash theme={null}
    npx -y create-solana-dapp@latest -t solana-foundation/templates/community/phantom-embedded-react
    ```
  </Tab>

  <Tab title="pnpm">
    ```bash theme={null}
    pnpm create solana-dapp@latest -t solana-foundation/templates/community/phantom-embedded-react
    ```
  </Tab>

  <Tab title="yarn">
    ```bash theme={null}
    yarn create solana-dapp -t solana-foundation/templates/community/phantom-embedded-react
    ```
  </Tab>

  <Tab title="bun">
    ```bash theme={null}
    bun create solana-dapp@latest -t solana-foundation/templates/community/phantom-embedded-react
    ```
  </Tab>
</Tabs>

Run the command above in your terminal to get started.

[View template on Solana Templates →](https://solana.com/developers/templates/phantom-embedded-react)

***

## Features

* Built for React: Provides React hooks (`usePhantom`, `useModal`) and a provider component for app-level configuration.
* Multi-chain support: Solana and Ethereum with dedicated hooks.
* Connection modal: Built-in, customizable modal for connecting users to Phantom.
* Flexible authentication providers: OAuth (Google, Apple) and the Phantom browser extension.
* User wallet integration: Connects to existing Phantom user wallets using Phantom Connect.
* TypeScript support: Fully typed API surface.

## Security

The Phantom Connect React SDK connects to existing Phantom user wallets, ensuring:

* Users control their own wallets and private keys.
* Integration with Phantom's secure wallet infrastructure.
* No private key handling in your application.
* User maintains full control of their assets.

## Prerequisites

<Warning>
  **Phantom Portal is not accepting new applications at this time.** New sign-ups for Phantom Connect SDK access and new app submissions to the Phantom app directory are paused. Existing Portal apps and App IDs are not affected.
</Warning>

* Use an existing app: Sign in to the [Phantom Portal](https://phantom.com/portal/) and select your app.
* Obtain your App ID:
  * In Phantom Portal, expand your app in the left navigation, then select **Set Up**.
  * Your App ID appears at the top of the page.
* Allowlist your domains and redirect URLs: Add your app's domains and redirect URLs in the Phantom Portal to enable wallet connections.

## Authentication configuration

When using OAuth providers (google, apple), you'll need to configure authentication options:

```tsx theme={null}
authOptions: {
  redirectUrl: "https://yourapp.com/auth/callback", // Your callback page
}
```

**Important notes about `redirectUrl`:**

* Must be an existing page/route in your application
* Must be whitelisted in your Phantom Portal app configuration
* This is where users will be redirected after completing OAuth authentication
* Required for google and apple providers
* Not required for injected provider

## Installation

```bash theme={null}
npm install @phantom/react-sdk
```

## Dependencies

Install additional dependencies based on the networks you want to support:

| Network support | Required dependencies |
| - | - |
| Solana | `@solana/web3.js` OR `@solana/kit` |
| Ethereum/EVM | `viem` |

Example for Solana and Ethereum support:

```bash theme={null}
npm install @phantom/react-sdk @solana/web3.js viem
```

## Quick start

```tsx theme={null}
import { PhantomProvider, useModal, darkTheme, usePhantom } from "@phantom/react-sdk";
import { AddressType } from "@phantom/browser-sdk";

function App() {
  return (
    <PhantomProvider
      config={{
        providers: ["google", "apple", "injected"], // Enabled auth methods
        appId: "your-app-id", // Get your app ID from phantom.com/portal
        addressTypes: [AddressType.solana, AddressType.ethereum],
        authOptions: {
          redirectUrl: "https://yourapp.com/auth/callback", // Must be whitelisted in Phantom Portal
        },
      }}
      theme={darkTheme}
      appIcon="https://your-app.com/icon.png"
      appName="Your App Name"
    >
      <WalletComponent />
    </PhantomProvider>
  );
}

function WalletComponent() {
  const { open, close, isOpened } = useModal();
  const { isConnected, user } = usePhantom();

  if (isConnected) {
    return (
      <div>
        <p>Connected</p>
      </div>
    );
  }

  return <button onClick={open}>Connect Wallet</button>;
}
```

## Connection Modal

The SDK includes a built-in connection modal UI that provides a user-friendly interface for connecting to Phantom. The modal supports multiple connection methods (Google, Apple, browser extension) and handles all connection logic automatically.

### Using the Modal with useModal Hook

To use the modal, pass a `theme` prop to `PhantomProvider` and use the `useModal()` hook to control visibility:

```tsx theme={null}
import { PhantomProvider, useModal, darkTheme, usePhantom } from "@phantom/react-sdk";
import { AddressType } from "@phantom/browser-sdk";

function App() {
  return (
    <PhantomProvider
      config={{
        providers: ["google", "apple", "injected"],
        appId: "your-app-id",
        addressTypes: [AddressType.solana, AddressType.ethereum],
      }}
      theme={darkTheme} // or lightTheme, or custom theme object
      appIcon="https://your-app.com/icon.png"
      appName="Your App Name"
    >
      <WalletComponent />
    </PhantomProvider>
  );
}

function WalletComponent() {
  const { open, close, isOpened } = useModal();
  const { isConnected } = usePhantom();

  if (isConnected) {
    return (
      <div>
        <p>Connected</p>
      </div>
    );
  }

  return <button onClick={open}>Connect Wallet</button>;
}
```

**Modal features:**

* **Multiple auth providers**: Google, Apple, browser extension
* **Automatic provider detection**: Shows browser extension option when Phantom is installed
* **Error handling**: Clear error messages displayed in the modal
* **Loading states**: Visual feedback during connection attempts
* **Responsive design**: Optimized for both mobile and desktop

### ConnectButton Component

A ready-to-use button component that handles the complete connection flow:

```tsx theme={null}
import { ConnectButton, AddressType } from "@phantom/react-sdk";

function Header() {
  return (
    <div>
      {/* Default: Shows first available address */}
      <ConnectButton />

      {/* Show specific address type */}
      <ConnectButton addressType={AddressType.solana} />
      <ConnectButton addressType={AddressType.ethereum} />

      {/* Full width button */}
      <ConnectButton fullWidth />
    </div>
  );
}
```

ConnectButton features:

* When disconnected: Opens connection modal with auth provider options
* When connected: Displays truncated address and opens wallet management modal
* Uses theme styling for consistent appearance

### ConnectBox component

An inline embedded component that displays the connection UI directly in your page layout (without a modal backdrop). Perfect for auth callback pages or when you want a more integrated connection experience. The component automatically handles all connection states including loading, error, and success during the auth callback flow.

<Frame>
  <img src="https://mintcdn.com/phantom-e50e2e68/6Jx1knw-O3z4Ex2i/resources/images/phantom-connect/connect-box-component.png?fit=max&auto=format&n=6Jx1knw-O3z4Ex2i&q=85&s=3237ac1f40c9034f8488362ebe3bc7c5" alt="ConnectBox component showing login options" width="686" height="1032" data-path="resources/images/phantom-connect/connect-box-component.png" />
</Frame>

```tsx theme={null}
import { ConnectBox } from "@phantom/react-sdk";

function AuthCallbackPage() {
  return (
    <div>
      <h1>Connecting to Phantom...</h1>
      <ConnectBox />
    </div>
  );
}
```

Props:

| Property | Type | Default | Description |
| - | - | - | - |
| `maxWidth` | `string \| number` | `"350px"` | Maximum width of the box |
| `transparent` | `boolean` | `false` | Removes background, border, and shadow for a transparent appearance |
| `appIcon` | `string` | — | URL to your app icon (optional, can also be set via `PhantomProvider`) |
| `appName` | `string` | — | Your app name (optional, can also be set via `PhantomProvider`) |

**Usage Examples:**

```tsx theme={null}
import { ConnectBox } from "@phantom/react-sdk";

// Default usage
<ConnectBox />

// Custom width
<ConnectBox maxWidth="500px" />

// Transparent (no background/border)
<ConnectBox transparent />

// Custom width with transparent
<ConnectBox maxWidth={600} transparent />
```

**ConnectBox Features:**

* **Inline embedded**: Renders directly in page flow (not as a floating modal)
* **Auto state management**: Automatically shows connection/login UI when disconnected, wallet info when connected
* **Auth callback support**: Handles loading and error states during OAuth callback flows
* **No close button**: Designed for embedded use cases where users shouldn't dismiss the UI
* **Theme-aware**: Uses your configured theme for consistent styling

<Tip>
  **Use ConnectBox for auth callback pages**: When using OAuth providers (Google, Apple), users are redirected to your callback URL after authentication. Place `ConnectBox` on this page to automatically handle the auth flow completion with proper loading and error states.
</Tip>

## Theming

The SDK includes pre-built themes and supports full customization to match your app's design.

### Pre-built themes

Use the included `darkTheme` or `lightTheme`:

```tsx theme={null}
import { PhantomProvider, darkTheme, lightTheme } from "@phantom/react-sdk";

// Dark theme
<PhantomProvider config={config} theme={darkTheme} appIcon="..." appName="...">
  <App />
</PhantomProvider>

// Light theme
<PhantomProvider config={config} theme={lightTheme} appIcon="..." appName="...">
  <App />
</PhantomProvider>
```

### Custom themes

Create a custom theme object to fully control the modal's appearance:

```tsx theme={null}
const customTheme = {
  background: "#1a1a1a",         // Background color for modal
  text: "#ffffff",               // Primary text color
  secondary: "#98979C",          // Secondary color for text, borders, dividers
  brand: "#ab9ff2",              // Brand/primary action color
  error: "#ff4444",              // Error state color
  success: "#00ff00",            // Success state color
  borderRadius: "16px",          // Border radius for buttons and modal
  overlay: "rgba(0, 0, 0, 0.8)", // Overlay background color (with opacity)
};

<PhantomProvider config={config} theme={customTheme} appIcon="..." appName="...">
  <App />
</PhantomProvider>
```

| Property | Description | Example |
| - | - | - |
| `background` | Modal background color | `"#1a1a1a"` |
| `text` | Primary text color | `"#ffffff"` |
| `secondary` | Secondary text, borders, and dividers | `"#98979C"` |
| `brand` | Brand/primary action color | `"#ab9ff2"` |
| `error` | Error state color | `"#ff4444"` |
| `success` | Success state color | `"#00ff00"` |
| `borderRadius` | Border radius for buttons and modal | `"16px"` |
| `overlay` | Modal overlay background (supports opacity) | `"rgba(0, 0, 0, 0.8)"` |

<Warning>
  The `secondary` color must be a hex color value (for example, `#98979C`) as it's used to derive auxiliary colors with opacity.
</Warning>

## Chain-Specific Hooks

The React SDK provides dedicated hooks for each blockchain:

### useSolana hook

```tsx theme={null}
import { useSolana } from "@phantom/react-sdk";

function SolanaOperations() {
  const { solana, isAvailable } = useSolana();

  // Check if Solana is available before using it
  if (!isAvailable) {
    return <div>Solana is not available for the current wallet</div>;
  }

  const signMessage = async () => {
    const signature = await solana.signMessage("Hello Solana!");
    console.log("Signature:", signature);
  };

  const signAndSendTransaction = async () => {
    const result = await solana.signAndSendTransaction(transaction);
    console.log("Transaction sent:", result.hash);
  };

  const switchNetwork = async () => {
    await solana.switchNetwork('devnet');
  };

  return (
    <div>
      <button onClick={signMessage}>Sign Message</button>
      <button onClick={signAndSendTransaction}>Send Transaction</button>
      <button onClick={switchNetwork}>Switch to Devnet</button>
      <p>Connected: {solana.isConnected ? 'Yes' : 'No'}</p>
    </div>
  );
}
```

### useEthereum hook

<Info>
  EVM support for Phantom Connect embedded wallets will go live later in 2026.
</Info>

```tsx theme={null}
import { useEthereum } from "@phantom/react-sdk";

function EthereumOperations() {
  const { ethereum, isAvailable } = useEthereum();

  // Check if Ethereum is available before using it
  if (!isAvailable) {
    return <div>Ethereum is not available for the current wallet</div>;
  }

  const signPersonalMessage = async () => {
    const accounts = await ethereum.getAccounts();
    const signature = await ethereum.signPersonalMessage("Hello Ethereum!", accounts[0]);
    console.log("Signature:", signature);
  };

  const sendTransaction = async () => {
    const result = await ethereum.sendTransaction({
      to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
      value: "1000000000000000000", // 1 ETH in wei
      gas: "21000",
    });
    console.log("Transaction sent:", result.hash);
  };

  const switchChain = async () => {
    await ethereum.switchChain(137); // Switch to Polygon
  };

  return (
    <div>
      <button onClick={signPersonalMessage}>Sign Personal Message</button>
      <button onClick={sendTransaction}>Send Transaction</button>
      <button onClick={switchChain}>Switch to Polygon</button>
      <p>Connected: {ethereum.isConnected ? 'Yes' : 'No'}</p>
    </div>
  );
}
```

<Warning>
  **Monad support has been deprecated.**
</Warning>

**Supported EVM Networks:**

| Network | Chain ID | Usage |
| - | - | - |
| Ethereum Mainnet | `1` | `ethereum.switchChain(1)` |
| Ethereum Sepolia | `11155111` | `ethereum.switchChain(11155111)` |
| Polygon Mainnet | `137` | `ethereum.switchChain(137)` |
| Polygon Amoy | `80002` | `ethereum.switchChain(80002)` |
| Base Mainnet | `8453` | `ethereum.switchChain(8453)` |
| Base Sepolia | `84532` | `ethereum.switchChain(84532)` |
| Arbitrum One | `42161` | `ethereum.switchChain(42161)` |
| Arbitrum Sepolia | `421614` | `ethereum.switchChain(421614)` |
| Monad Mainnet (Deprecated) | `143` | `ethereum.switchChain(143)` |
| Monad Testnet (Deprecated) | `10143` | `ethereum.switchChain(10143)` |

## Auto-Confirm Hook (Injected Provider Only)

The SDK provides auto-confirm functionality that allows automatic transaction confirmation for specified chains.

### useAutoConfirm hook

```tsx theme={null}
import { useAutoConfirm, NetworkId } from "@phantom/react-sdk";

function AutoConfirmControls() {
  const {
    enable,
    disable, 
    status,
    supportedChains,
    isLoading,
    error,
  } = useAutoConfirm();

  const handleEnable = async () => {
    // Enable auto-confirm for specific chains
    const result = await enable({
      chains: [NetworkId.SOLANA_DEVNET, NetworkId.ETHEREUM_MAINNET]
    });
    console.log("Auto-confirm enabled:", result);
  };

  const handleDisable = async () => {
    await disable();
    console.log("Auto-confirm disabled");
  };

  return (
    <div>
      <p>Status: {status?.enabled ? "Enabled" : "Disabled"}</p>
      <button onClick={handleEnable} disabled={isLoading}>
        Enable Auto-Confirm
      </button>
      <button onClick={handleDisable} disabled={isLoading}>
        Disable Auto-Confirm
      </button>
    </div>
  );
}
```

## Wallet Discovery Hook

### useDiscoveredWallets

Get discovered injected wallets with automatic loading and error states. Discovers wallets using Wallet Standard (Solana) and EIP-6963 (Ethereum) standards.

```tsx theme={null}
import { useDiscoveredWallets } from "@phantom/react-sdk";

function WalletSelector() {
  const { wallets, isLoading, error, refetch } = useDiscoveredWallets();

  if (isLoading) {
    return <div>Discovering wallets...</div>;
  }

  if (error) {
    return <div>Error discovering wallets: {error.message}</div>;
  }

  return (
    <div>
      <h3>Available Wallets</h3>
      {wallets.map((wallet) => (
        <div key={wallet.id}>
          <img src={wallet.icon} alt={wallet.name} width={24} />
          <span>{wallet.name}</span>
        </div>
      ))}
      <button onClick={refetch}>Refresh</button>
    </div>
  );
}
```

Returns:

| Property | Type | Description |
| - | - | - |
| `wallets` | `InjectedWalletInfo[]` | Array of discovered wallet information |
| `isLoading` | `boolean` | `true` while discovery is in progress |
| `error` | `Error \| null` | Error object if discovery fails |
| `refetch` | `() => Promise<void>` | Function to manually refresh the wallet list |

## SDK Initialization

The SDK provides an `isLoading` state to track when initialization and autoconnect are in progress:

```tsx theme={null}
import { useConnect, usePhantom } from "@phantom/react-sdk";

function App() {
  const { isLoading } = usePhantom();
  const { connect } = useConnect();

  // Show loading state while SDK initializes
  if (isLoading) {
    return (
      <div>
        <h1>Initializing Phantom SDK...</h1>
        <p>Please wait...</p>
      </div>
    );
  }

  // SDK is ready
  return (
    <div>
      <h1>Welcome!</h1>
      <button onClick={() => connect({ provider: "injected" })}>
        Connect Wallet
      </button>
    </div>
  );
}
```

## Debug Configuration

Configure debug logging by passing a `debugConfig` prop to `PhantomProvider`:

```tsx theme={null}
import { PhantomProvider, DebugLevel } from "@phantom/react-sdk";

function App() {
  const [debugMessages, setDebugMessages] = useState([]);

  const debugConfig = {
    enabled: true,
    level: DebugLevel.INFO,
    callback: (message) => {
      setDebugMessages((prev) => [...prev, message]);
    },
  };

  return (
    <PhantomProvider config={config} debugConfig={debugConfig}>
      <YourApp />
    </PhantomProvider>
  );
}
```

Debug configuration properties:

| Property | Type | Description |
| - | - | - |
| `enabled` | `boolean` | Enable debug logging |
| `level` | `DebugLevel` | Debug level (ERROR, WARN, INFO, DEBUG) |
| `callback` | `(message: DebugMessage) => void` | Custom debug message handler |

## Available hooks

| Hook | Purpose | Returns |
| - | - | - |
| `useModal` | Control the connection modal | `{ open, close, isOpened }` |
| `usePhantom` | Access wallet/user state | `{ isConnected, isLoading, user, wallet }` |
| `useConnect` | Connect to wallet | `{ connect, isConnecting, isLoading, error }` |
| `useAccounts` | Get wallet addresses | `WalletAddress[]` or `null` |
| `useIsExtensionInstalled` | Check extension status | `{ isLoading, isInstalled }` |
| `useDisconnect` | Disconnect from wallet | `{ disconnect, isDisconnecting }` |
| `useAutoConfirm` | Auto-confirm management (injected only) | `{ enable, disable, status, supportedChains, ... }` |
| `useDiscoveredWallets` | Get discovered injected wallets | `{ wallets, isLoading, error, refetch }` |
| `useSolana` | Solana chain operations | `{ solana, isAvailable }` |
| `useEthereum` | Ethereum chain operations | `{ ethereum, isAvailable }` |
| `useTheme` | Access current theme | `PhantomTheme` |

## What you can do

<CardGroup cols={3}>
  <Card title="Connect to wallets" icon="plug" href="/sdks/react-sdk/connect">
    Learn how to connect to Phantom user wallets with React hooks
  </Card>

  <Card title="Sign messages" icon="signature" href="/sdks/react-sdk/sign-messages">
    Implement message signing for authentication and verification
  </Card>

  <Card title="Sign and send transactions" icon="paper-plane" href="/sdks/react-sdk/sign-and-send-transaction">
    Handle transaction signing and broadcasting across blockchains
  </Card>
</CardGroup>

## Starter kits and examples

Get started quickly with production-ready React templates:

<CardGroup cols={2}>
  <Card title="React SDK demo app" icon="react" href="https://github.com/phantom/phantom-connect-sdk/tree/main/examples/react-sdk-demo-app">
    Full-featured React example with wallet connection, signing, and transactions
  </Card>

  <Card title="Next.js example" icon="rocket" href="https://github.com/phantom/phantom-connect-sdk/tree/main/examples/with-nextjs">
    Complete Next.js integration with Phantom React SDK
  </Card>

  <Card title="Wagmi Integration" icon="code" href="https://github.com/phantom/phantom-connect-sdk/tree/main/examples/with-wagmi">
    Use Phantom SDK alongside Wagmi for enhanced Ethereum support
  </Card>

  <Card title="Connect modal example" icon="window-restore" href="https://github.com/phantom/phantom-connect-sdk/tree/main/examples/with-modal">
    Drop-in connect modal example showing the full sign-in flow
  </Card>

  <Card title="All examples" icon="github" href="https://github.com/phantom/phantom-connect-sdk/tree/main/examples">
    Browse all example applications on GitHub
  </Card>
</CardGroup>

## Additional resources

<CardGroup cols={3}>
  <Card title="SDK overview" icon="book" href="/wallet-sdks-overview">
    Compare all Phantom SDKs and choose the right one
  </Card>

  <Card title="Phantom Connect" icon="link" href="/phantom-connect">
    Learn about authentication flows and user experience
  </Card>

  <Card title="JWT authentication" icon="key" href="/sdks/guides/wallet-authentication-with-jwts">
    Implement custom JWT-based authentication
  </Card>
</CardGroup>
