React hooks for integrating Phantom wallet functionality into React applications with chain-specific operations.
npm install @phantom/react-sdkReact hooks for integrating Phantom wallet functionality into React applications with chain-specific operations.
``bash`
npm install @phantom/react-sdk
Install additional dependencies based on the networks you want to support:
| Network Support | Required Dependencies |
| --------------- | ---------------------------------- |
| Solana | @solana/web3.js OR @solana/kit |viem
| Ethereum/EVM | |
Example for Solana + Ethereum support (using @solana/web3.js):
`bash`
npm install @phantom/react-sdk @solana/web3.js viem
Example for Solana + Ethereum support (using @solana/kit):
`bash`
npm install @phantom/react-sdk @solana/kit viem
`tsx
import { PhantomProvider, useConnect, useSolana, useEthereum } from "@phantom/react-sdk";
import { AddressType } from "@phantom/browser-sdk";
function App() {
return (
providers: ["injected"], // Only allow Phantom browser extension
addressTypes: [AddressType.solana, AddressType.ethereum],
}}
>
);
}
function WalletComponent() {
const { connect, isConnecting } = useConnect();
const { solana } = useSolana();
const { ethereum } = useEthereum();
const handleConnect = async () => {
const { addresses } = await connect({ provider: "injected" });
console.log("Connected addresses:", addresses);
};
const signSolanaMessage = async () => {
const signature = await solana.signMessage("Hello Solana!");
console.log("Solana signature:", signature);
};
const signEthereumMessage = async () => {
const accounts = await ethereum.getAccounts();
const signature = await ethereum.signPersonalMessage("Hello Ethereum!", accounts[0]);
console.log("Ethereum signature:", signature);
};
return (
$3
`tsx
import { PhantomProvider } from "@phantom/react-sdk";
import { AddressType } from "@phantom/browser-sdk";function App() {
return (
config={{
providers: ["google", "apple", "phantom", "injected"], // Allow all auth methods
appId: "your-app-id", // Get your app ID from phantom.com/portal (required for embedded providers)
addressTypes: [AddressType.solana, AddressType.ethereum],
}}
>
);
}
`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, Phantom Login, browser extension) and handles all connection logic automatically.
$3
To use the modal, pass a
theme prop to PhantomProvider and use the useModal() hook to control visibility:`tsx
import { PhantomProvider, useModal, darkTheme, usePhantom } from "@phantom/react-sdk";
import { AddressType } from "@phantom/browser-sdk";function App() {
return (
config={{
providers: ["google", "apple", "phantom", "injected"],
appId: "your-app-id",
addressTypes: [AddressType.solana, AddressType.ethereum],
}}
theme={darkTheme}
appIcon="https://your-app.com/icon.png"
appName="Your App Name"
>
);
}
function WalletComponent() {
const { open, close, isOpened } = useModal();
const { isConnected, user } = usePhantom();
if (isConnected) {
return (
Connected as {user?.email || "Unknown"}
);
} return ;
}
`Modal Features:
- Multiple Auth Providers: Google, Apple, Phantom Login, browser extension
- Automatic Provider Detection: Shows browser extension option when Phantom is installed
- Mobile Support: Displays deeplink option for Phantom mobile app on mobile devices
- Error Handling: Clear error messages displayed in the modal
- Loading States: Visual feedback during connection attempts
- Responsive Design: Optimized for both mobile and desktop
$3
Control the connection modal visibility:
`tsx
import { useModal } from "@phantom/react-sdk";function ConnectButton() {
const { open, close, isOpened } = useModal();
return (
Modal is {isOpened ? "open" : "closed"}
);
}
`Returns:
-
open() - Function to open the modal
- close() - Function to close the modal
- isOpened - Boolean indicating if modal is currently visible$3
A ready-to-use button component that handles the complete connection flow. When disconnected, it shows a "Connect Wallet" button that opens the connection modal. When connected, it displays the truncated wallet address and opens the wallet management modal on click.
`tsx
import { ConnectButton, AddressType } from "@phantom/react-sdk";function Header() {
return (
{/ Default: Shows first available address /}
{/ Show specific address type /}
{/ Full width button /}
);
}
`Props:
-
addressType?: AddressType - Specify which address type to display when connected (e.g., AddressType.solana, AddressType.ethereum). If not specified, shows the first available address.
- fullWidth?: boolean - Whether the button should take full width of its container. Default: falseFeatures:
- When disconnected: Opens connection modal with auth provider options (Google, Apple, Phantom Login, browser extension)
- When connected: Displays truncated address (e.g., "5Gv8r2...k3Hn") and opens wallet management modal on click
- Wallet modal: Shows all connected addresses and provides a disconnect button
- Uses theme styling for consistent appearance
- Fully clickable in both states
$3
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.
`tsx
import { ConnectBox } from "@phantom/react-sdk";function AuthCallbackPage() {
return (
Connecting to Phantom...
);
}
`Props:
-
maxWidth?: string | number - Maximum width of the box. Can be a string (e.g., "500px") or number (e.g., 500). Default: "350px"
- transparent?: boolean - When true, removes background, border, and shadow for a transparent appearance. Default: false
- 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
import { ConnectBox } from "@phantom/react-sdk";// Default usage
// Custom width
// Transparent (no background/border)
// Custom width with transparent
`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
- Responsive: Adapts to mobile and desktop layouts
Use Cases:
- Auth callback pages (e.g.,
/auth/callback) where users return from OAuth providers
- Embedded wallet connection flows in your app's layout
- Custom connection pages where you want full control over the page design$3
When using embedded authentication providers (Google, Apple, Phantom Login, etc.), users are redirected to your app's callback URL after authentication. The SDK automatically handles the callback and completes the connection. Here's how to build a callback page if you're not using
ConnectBox:Basic Auth Callback Page:
`tsx
import { usePhantom, useConnect, useAccounts } from "@phantom/react-sdk";
import { useNavigate } from "react-router-dom"; // or your routerfunction AuthCallbackPage() {
const navigate = useNavigate();
const { isConnected } = usePhantom();
const { isConnecting, error: connectError } = useConnect();
const addresses = useAccounts();
const handleGoHome = () => {
navigate("/");
};
// Loading state - SDK is processing the callback
if (isConnecting) {
return (
Connecting to wallet...
Please wait while we complete your authentication.
);
} // Success state - connection completed
if (isConnected && addresses && addresses.length > 0) {
return (
Authentication Successful
You are now connected to your wallet.
Addresses:
{addresses.map((addr, index) => (
{addr.addressType}: {addr.address}
))}
);
} // Error state - connection failed
if (connectError) {
return (
Authentication Failed
{connectError.message || "An unknown error occurred during authentication."}
);
} // Default state (shouldn't normally reach here)
return (
Processing authentication...
);
}
`Key Points:
- The SDK's
autoConnect() automatically processes the callback URL parameters when the page loads
- Use useConnect() to access isConnecting and error states during the callback flow
- Use usePhantom() to check isConnected status
- Use useAccounts() to get connected wallet addresses
- The connection state will automatically update as the SDK processes the callback
- You can monitor connectError to handle authentication failuresRouter Setup:
Make sure your callback route is configured in your router:
`tsx
import { Routes, Route } from "react-router-dom";
import { PhantomProvider } from "@phantom/react-sdk";function App() {
return (
} />
} />
);
}
`Note: For a simpler implementation, consider using the
ConnectBox component which handles all these states automatically.Theming
Customize the modal appearance by passing a theme object to the
PhantomProvider. The SDK includes two built-in themes: darkTheme (default) and lightTheme.$3
`tsx
import { PhantomProvider, darkTheme, lightTheme } from "@phantom/react-sdk";// Use dark theme (default)
// Use light theme
`$3
You can pass a partial theme object to customize specific properties:
`tsx
import { PhantomProvider } from "@phantom/react-sdk";const customTheme = {
background: "#1a1a1a",
text: "#ffffff",
secondary: "#98979C",
brand: "#ab9ff2",
error: "#ff4444",
success: "#00ff00",
borderRadius: "16px",
overlay: "rgba(0, 0, 0, 0.8)",
};
;
`$3
| Property | Type | Description |
| -------------- | -------- | --------------------------------------------------------- |
|
background | string | Background color for modal |
| text | string | Primary text color |
| secondary | string | Secondary color for text, borders, dividers (must be hex) |
| brand | string | Brand/primary action color |
| error | string | Error state color |
| success | string | Success state color |
| borderRadius | string | Border radius for buttons and modal |
| overlay | string | Overlay background color (with opacity) |Note: The
secondary color must be a hex color value (e.g., #98979C) as it's used to derive auxiliary colors with opacity.$3
If you need to access the current theme in your own components, use the
useTheme() hook:`tsx
import { useTheme } from "@phantom/react-sdk";function CustomComponent() {
const theme = useTheme();
return
Themed content;
}
`Connection Flow
The React SDK follows a clear connection pattern:
1. Provider Setup: Wrap your app with
PhantomProvider
2. Connection: Use useConnect() to establish wallet connection
3. Chain Operations: Use chain-specific hooks (useSolana(), useEthereum()) for transactions and signing`tsx
function WalletExample() {
const { connect } = useConnect();
const { solana } = useSolana();
const { ethereum } = useEthereum(); // 1. Connect first (provider parameter is required)
const handleConnect = async () => {
await connect({ provider: "injected" });
};
// 2. Then use chain-specific operations
const sendSolanaTransaction = async () => {
const result = await solana.signAndSendTransaction(transaction);
};
const sendEthereumTransaction = async () => {
const result = await ethereum.sendTransaction(transaction);
};
}
`$3
The
connect() method requires a provider parameter and automatically switches between providers based on the authentication method you specify:`tsx
const { connect } = useConnect();// Connect with injected provider (Phantom extension)
// Automatically switches to injected provider if not already using it
await connect({
provider: "injected",
});
// Connect with Google authentication (embedded provider)
// Automatically switches to embedded provider if not already using it
await connect({
provider: "google",
});
// Connect with Apple authentication (embedded provider)
// Automatically switches to embedded provider if not already using it
await connect({
provider: "apple",
});
// Connect with Phantom authentication (embedded provider)
// Uses Phantom extension or mobile app for authentication
// Automatically switches to embedded provider if not already using it
await connect({
provider: "phantom",
});
// Connect with JWT authentication (embedded provider)
await connect({
provider: "jwt",
jwtToken: "your-jwt-token",
});
`SDK Initialization
The SDK provides an
isLoading state to track when initialization and autoconnect are in progress. This is useful for showing loading states before your app is ready.`tsx
import { useConnect, usePhantom } from "@phantom/react-sdk";function App() {
const { isLoading } = usePhantom();
const { connect } = useConnect();
// Show loading state while SDK initializes
if (isLoading) {
return (
Initializing Phantom SDK...
Please wait...
);
} // SDK is ready
return (
Welcome!
);
}
`Authentication Providers
The SDK supports multiple authentication providers that you configure via the
providers array:$3
-
"injected" - Phantom browser extension
- "google" - Google OAuth
- "apple" - Apple ID
- "phantom" - Phantom Login
- "deeplink" - Deeplink to Phantom mobile app (only renders on mobile devices)$3
Browser Extension Only
`tsx
config={{
providers: ["injected"], // Only allow browser extension
addressTypes: [AddressType.solana, AddressType.ethereum],
}}
>
`Multiple Authentication Methods
`tsx
config={{
providers: ["google", "apple", "phantom", "injected", "deeplink"], // Allow all methods
appId: "your-app-id", // Required for embedded providers
addressTypes: [AddressType.solana, AddressType.ethereum],
}}
>
`Mobile Deeplink Support
The
"deeplink" provider enables a button that opens the Phantom mobile app on mobile devices. This button only appears on mobile devices when the Phantom browser extension is not installed. When clicked, it redirects users to the Phantom mobile app to complete authentication.`tsx
config={{
providers: ["google", "apple", "phantom", "deeplink"], // Include deeplink for mobile support
appId: "your-app-id", // Required for deeplink
addressTypes: [AddressType.solana, AddressType.ethereum],
}}
>
`$3
When using embedded providers (google, apple, phantom, etc.), you can specify the wallet type using
embeddedWalletType. The default is "user-wallet":- Uses Phantom authentication - user logs in with existing account
- Potentially funded - brings existing wallet balance
- Connected to user's Phantom ecosystem
`tsx
config={{
providers: ["google", "apple", "phantom"],
appId: "your-app-id",
addressTypes: [AddressType.solana, AddressType.ethereum],
embeddedWalletType: "user-wallet", // default, can be omitted
}}
>
`Available Hooks
$3
#### useConnect
Connect to wallet:
`tsx
import { useConnect } from "@phantom/react-sdk";function ConnectButton() {
const { connect, isConnecting, isLoading, error } = useConnect();
const handleConnect = async () => {
try {
const { addresses } = await connect({ provider: "injected" });
console.log("Connected addresses:", addresses);
} catch (err) {
console.error("Failed to connect:", err);
}
};
// Wait for SDK to finish initializing before showing connect button
if (isLoading) {
return
Loading...;
} return (
);
}
`#### useAccounts
Get connected wallet addresses:
`tsx
import { useAccounts } from "@phantom/react-sdk";function WalletAddresses() {
const addresses = useAccounts();
if (!addresses) {
return
Not connected;
} return (
{addresses.map((addr, index) => (
{addr.addressType}: {addr.address}
))}
);
}
`#### useDisconnect
Disconnect from wallet:
`tsx
import { useDisconnect } from "@phantom/react-sdk";function DisconnectButton() {
const { disconnect, isDisconnecting } = useDisconnect();
return (
);
}
`#### useIsExtensionInstalled
Check if the Phantom browser extension is installed (for injected provider):
`tsx
import { useIsExtensionInstalled } from "@phantom/react-sdk";function ExtensionStatus() {
const { isLoading, isInstalled } = useIsExtensionInstalled();
if (isLoading) {
return
Checking for Phantom extension...;
} return (
{isInstalled ? (
ā
Phantom extension is installed!
) : (
ā Phantom extension not found.{" "}
Install here
)}
);
}
`#### useIsPhantomLoginAvailable
Check if Phantom Login is available (requires extension installed and
phantom_login feature support):`tsx
import { useIsPhantomLoginAvailable } from "@phantom/react-sdk";function PhantomLoginButton() {
const { isLoading, isAvailable } = useIsPhantomLoginAvailable();
const { connect } = useConnect();
if (isLoading) {
return
Checking Phantom Login availability...;
} if (!isAvailable) {
return null; // Don't show button if Phantom Login is not available
}
return ;
}
`$3
#### useSolana
Hook for Solana chain operations:
`tsx
import { useSolana } from "@phantom/react-sdk";
import { VersionedTransaction, TransactionMessage, SystemProgram, PublicKey, Connection } from "@solana/web3.js";function SolanaOperations() {
const { solana, isAvailable } = useSolana();
// Check if Solana is available before using it
if (!isAvailable) {
return
Solana is not available for the current wallet;
} const signMessage = async () => {
const signature = await solana.signMessage("Hello Solana!");
console.log("Signature:", signature);
};
const signAndSendTransaction = async () => {
// Create transaction
const connection = new Connection("https://api.mainnet-beta.solana.com");
const { blockhash } = await connection.getLatestBlockhash();
const fromAddress = await solana.getPublicKey();
const transferInstruction = SystemProgram.transfer({
fromPubkey: new PublicKey(fromAddress),
toPubkey: new PublicKey(toAddress),
lamports: 1000000, // 0.001 SOL
});
const messageV0 = new TransactionMessage({
payerKey: new PublicKey(fromAddress),
recentBlockhash: blockhash,
instructions: [transferInstruction],
}).compileToV0Message();
const transaction = new VersionedTransaction(messageV0);
// Sign and send
const result = await solana.signAndSendTransaction(transaction);
console.log("Transaction sent:", result.signature);
};
const switchNetwork = async () => {
await solana.switchNetwork("devnet");
};
return (
Connected: {solana.isConnected ? "Yes" : "No"}
);
}
`Available methods:
-
signMessage(message) - Sign a message
- signTransaction(transaction) - Sign without sending
- signAndSendTransaction(transaction) - Sign and send
- switchNetwork(network) - Switch between mainnet/devnet
- getPublicKey() - Get current public key
- isConnected - Connection status
- isAvailable - Provider availability (see note below)Note on
isAvailable:The
isAvailable property indicates whether the Solana chain is available for the currently connected wallet:- For embedded wallets (Google, Apple, Phantom Login, etc.):
isAvailable will be true for all networks configured in your addressTypes array, as embedded wallets support all configured networks.- For Phantom injected wallet:
isAvailable will be true for all networks configured in your addressTypes array, as Phantom supports multiple networks.- For other injected wallets (discovered via Wallet Standard or EIP-6963):
isAvailable depends on which networks the specific wallet supports. For example, if you connect to a wallet that only supports Ethereum, isAvailable will be false for Solana even if Solana is in your addressTypes configuration.Always check
isAvailable before attempting to use chain-specific methods when working with injected wallets that may not support all networks.#### useEthereum
Hook for Ethereum chain operations:
`tsx
import { useEthereum } from "@phantom/react-sdk";function EthereumOperations() {
const { ethereum, isAvailable } = useEthereum();
// Check if Ethereum is available before using it
if (!isAvailable) {
return
Ethereum is not available for the current wallet;
} const signPersonalMessage = async () => {
const accounts = await ethereum.getAccounts();
const signature = await ethereum.signPersonalMessage("Hello Ethereum!", accounts[0]);
console.log("Signature:", signature);
};
const signTypedData = async () => {
const accounts = await ethereum.getAccounts();
const typedData = {
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
{ name: "verifyingContract", type: "address" },
],
Mail: [
{ name: "from", type: "string" },
{ name: "to", type: "string" },
{ name: "contents", type: "string" },
],
},
primaryType: "Mail",
domain: {
name: "Ether Mail",
version: "1",
chainId: 1,
verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
},
message: {
from: "Alice",
to: "Bob",
contents: "Hello!",
},
};
const signature = await ethereum.signTypedData(typedData);
console.log("Typed data signature:", signature);
};
const signTransaction = async () => {
const signedTx = await ethereum.signTransaction({
to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
value: "1000000000000000000", // 1 ETH in wei
gas: "21000",
});
console.log("Transaction signed:", signedTx);
// Transaction is signed but not sent - you can broadcast it later
};
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 (
Connected: {ethereum.isConnected ? "Yes" : "No"}
);
}
`Available methods:
-
request(args) - EIP-1193 requests
- signPersonalMessage(message, address) - Sign personal message
- signTypedData(typedData) - Sign EIP-712 typed data
- signTransaction(transaction) - Sign transaction without sending
- sendTransaction(transaction) - Sign and send transaction
- switchChain(chainId) - Switch chains (accepts chain ID as number or a hex string)
- getChainId() - Get current chain ID
- getAccounts() - Get connected accounts
- isConnected - Connection status
- isAvailable - Provider availability (see note below)Note on
isAvailable:The
isAvailable property indicates whether the Ethereum chain is available for the currently connected wallet:- For embedded wallets (Google, Apple, Phantom Login, etc.):
isAvailable will be true for all networks configured in your addressTypes array, as embedded wallets support all configured networks.- For Phantom injected wallet:
isAvailable will be true for all networks configured in your addressTypes array, as Phantom supports multiple networks.- For other injected wallets (discovered via Wallet Standard or EIP-6963):
isAvailable depends on which networks the specific wallet supports. For example, if you connect to a wallet that only supports Solana, isAvailable will be false for Ethereum even if Ethereum is in your addressTypes configuration.Always check
isAvailable before attempting to use chain-specific methods when working with injected wallets that may not support all networks.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 | 143 | ethereum.switchChain(143) |
| Monad Testnet | 10143 | ethereum.switchChain(10143) |$3
#### useDiscoveredWallets
Hook to get discovered injected wallets with automatic loading and error states. Discovers wallets using Wallet Standard (Solana) and EIP-6963 (Ethereum) standards.
`tsx
import { useDiscoveredWallets } from "@phantom/react-sdk";function WalletSelector() {
const { wallets, isLoading, error, refetch } = useDiscoveredWallets();
// wallets: InjectedWalletInfo[] - Array of discovered wallets
// isLoading: boolean - Loading state during discovery
// error: Error | null - Error state if discovery fails
// refetch: () => Promise - Function to manually trigger discovery
}
`Returns:
-
wallets: InjectedWalletInfo[] - Array of discovered wallet information
- isLoading: boolean - true while discovery is in progress
- error: Error | null - Error object if discovery fails, null otherwise
- refetch: () => Promise - Async function to manually refresh the wallet listBehavior:
- Automatically fetches discovered wallets when the SDK becomes available
- If no wallets are found in the registry, triggers async
discoverWallets() to discover them
- Wallets are filtered based on the addressTypes configured in PhantomProvider
- Phantom wallet is automatically included if available$3
#### useAutoConfirm
Hook for managing auto-confirm functionality with the Phantom extension. Auto-confirm allows transactions to be automatically approved without user interaction for enabled chains.
> Note: This hook only works with the
injected provider type (Phantom browser extension). It will throw errors for embedded providers.`tsx
import { useAutoConfirm, NetworkId } from "@phantom/react-sdk";function AutoConfirmControls() {
const { enable, disable, status, supportedChains, isLoading, error, refetch } = useAutoConfirm();
const handleEnable = async () => {
try {
// Enable auto-confirm for specific chains
const result = await enable({
chains: [NetworkId.SOLANA_DEVNET, NetworkId.ETHEREUM_MAINNET],
});
console.log("Auto-confirm enabled:", result);
} catch (err) {
console.error("Failed to enable auto-confirm:", err);
}
};
const handleDisable = async () => {
try {
await disable();
console.log("Auto-confirm disabled");
} catch (err) {
console.error("Failed to disable auto-confirm:", err);
}
};
if (isLoading) {
return
Loading auto-confirm settings...;
} if (error) {
return
Error: {error.message};
} return (
Auto-Confirm Settings
Status: {status?.enabled ? "Enabled" : "Disabled"}
{status?.chains && (
Active Chains:
{status.chains.map(chain => (
- {chain}
))}
)}
Supported Chains:
{supportedChains?.chains && (
{supportedChains.chains.map(chain => (
- {chain}
))}
)}
);
}
`Hook Interface:
`typescript
interface UseAutoConfirmResult {
enable: (params: AutoConfirmEnableParams) => Promise;
disable: () => Promise;
status: AutoConfirmResult | null;
supportedChains: AutoConfirmSupportedChainsResult | null;
isLoading: boolean;
error: Error | null;
refetch: () => Promise;
}interface AutoConfirmEnableParams {
chains?: NetworkId[]; // Optional array of chains to enable
}
interface AutoConfirmResult {
enabled: boolean;
chains: NetworkId[];
}
interface AutoConfirmSupportedChainsResult {
chains: NetworkId[];
}
`Available Methods:
-
enable(params) - Enable auto-confirm for specific chains
- disable() - Disable auto-confirm completely
- refetch() - Refresh status and supported chains from extension
- status - Current auto-confirm status (enabled/disabled and active chains)
- supportedChains - List of chains that support auto-confirm
- isLoading - Loading state for operations
- error - Any errors from auto-confirm operationsUsage Notes:
- Auto-confirm automatically fetches status and supported chains when the hook initializes
- Only works with injected provider (Phantom extension)
- Throws errors for embedded providers
- Status is automatically updated after enable/disable operations
- Use
refetch() to manually refresh data from the extensionTransaction Examples
$3
`tsx
import { VersionedTransaction, TransactionMessage, SystemProgram, PublicKey, Connection } from "@solana/web3.js";
import { useSolana } from "@phantom/react-sdk";function SolanaExample() {
const { solana } = useSolana();
const sendTransaction = async () => {
// Get recent blockhash
const connection = new Connection("https://api.mainnet-beta.solana.com");
const { blockhash } = await connection.getLatestBlockhash();
// Create transfer instruction
const fromAddress = await solana.getPublicKey();
const transferInstruction = SystemProgram.transfer({
fromPubkey: new PublicKey(fromAddress),
toPubkey: new PublicKey(toAddress),
lamports: 1000000, // 0.001 SOL
});
// Create VersionedTransaction
const messageV0 = new TransactionMessage({
payerKey: new PublicKey(fromAddress),
recentBlockhash: blockhash,
instructions: [transferInstruction],
}).compileToV0Message();
const transaction = new VersionedTransaction(messageV0);
// Sign and send using chain-specific hook
const result = await solana.signAndSendTransaction(transaction);
console.log("Transaction sent:", result.signature);
};
return ;
}
`$3
`tsx
import {
createSolanaRpc,
pipe,
createTransactionMessage,
setTransactionMessageFeePayer,
setTransactionMessageLifetimeUsingBlockhash,
address,
compileTransaction,
} from "@solana/kit";
import { useSolana } from "@phantom/react-sdk";function SolanaKitExample() {
const { solana } = useSolana();
const sendTransaction = async () => {
const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
const userPublicKey = await solana.getPublicKey();
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
tx => setTransactionMessageFeePayer(address(userPublicKey), tx),
tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
);
const transaction = compileTransaction(transactionMessage);
// Sign and send using chain-specific hook
const result = await solana.signAndSendTransaction(transaction);
console.log("Transaction sent:", result.signature);
};
return ;
}
`$3
`tsx
import { parseEther, parseGwei, encodeFunctionData } from "viem";
import { useEthereum } from "@phantom/react-sdk";function EthereumExample() {
const { ethereum } = useEthereum();
const sendEth = async () => {
const result = await ethereum.sendTransaction({
to: "0x742d35Cc6634C0532925a3b8D4C8db86fB5C4A7E",
value: parseEther("1").toString(), // 1 ETH
gas: "21000",
gasPrice: parseGwei("20").toString(), // 20 gwei
});
console.log("ETH sent:", result.hash);
};
const sendToken = async () => {
const result = await ethereum.sendTransaction({
to: tokenContractAddress,
data: encodeFunctionData({
abi: erc20Abi,
functionName: "transfer",
args: [recipientAddress, parseEther("100")],
}),
gas: "50000",
maxFeePerGas: parseGwei("30").toString(),
maxPriorityFeePerGas: parseGwei("2").toString(),
});
console.log("Token sent:", result.hash);
};
return (
);
}
`Hooks Reference
Quick reference of all available hooks:
| Hook | Purpose | Returns |
| ---------------------------- | --------------------------------------- | --------------------------------------------------- |
|
useConnect | Connect to wallet | { connect, isConnecting, error } |
| useModal | Control connection modal | { open, close, isOpened } |
| useAccounts | Get wallet addresses | WalletAddress[] or null |
| useIsExtensionInstalled | Check extension status | { isLoading, isInstalled } |
| useIsPhantomLoginAvailable | Check Phantom Login availability | { isLoading, isAvailable } |
| 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 | { signMessage, signAndSendTransaction, ... } |
| useEthereum | Ethereum chain operations | { signPersonalMessage, sendTransaction, ... } |
| useTheme | Access current theme | PhantomTheme |
| usePhantom | Get provider context | { isConnected, isReady } |Configuration Reference
`typescript
interface PhantomSDKConfig {
// List of allowed authentication providers (REQUIRED)
providers: AuthProviderType[]; // e.g., ["google", "apple", "phantom", "injected"] addressTypes?: [AddressType, ...AddressType[]]; // Networks to enable (e.g., [AddressType.solana])
// Required when using embedded providers (google, apple, phantom)
appId?: string; // Your app ID from phantom.com/portal
// Optional configuration
apiBaseUrl?: string; // Phantom API base URL (optional, has default)
authOptions?: {
authUrl?: string; // Custom auth URL (optional, defaults to "https://connect.phantom.app/login")
redirectUrl?: string; // Custom redirect URL after authentication (optional)
};
embeddedWalletType?: "user-wallet"; // Wallet type (optional, defaults to "user-wallet")
autoConnect?: boolean; // Auto-connect to existing session (default: true when embedded providers used)
}
// Valid provider types
type AuthProviderType = "google" | "apple" | "phantom" | "injected";
`Debug Configuration
The React SDK supports separate debug configuration that can be changed without reinstantiating the underlying SDK, providing better performance.
$3
`typescript
interface PhantomDebugConfig {
enabled?: boolean; // Enable debug logging
level?: DebugLevel; // Debug level (ERROR, WARN, INFO, DEBUG)
callback?: DebugCallback; // Custom debug message handler
}
`$3
Pass the
debugConfig as a separate prop to PhantomProvider:`typescript
import { PhantomProvider, type PhantomSDKConfig, type PhantomDebugConfig, DebugLevel } from "@phantom/react-sdk";function App() {
const [debugLevel, setDebugLevel] = useState(DebugLevel.INFO);
const [debugMessages, setDebugMessages] = useState([]);
// SDK configuration - static, won't change when debug settings change
const config: PhantomSDKConfig = {
providers: ["google", "apple", "phantom"],
appId: "your-app-id",
addressTypes: [AddressType.solana, AddressType.ethereum],
// ... other config
};
// Debug configuration - separate to avoid SDK reinstantiation
const debugConfig: PhantomDebugConfig = {
enabled: true,
level: debugLevel,
callback: (message) => {
setDebugMessages(prev => [...prev, message]);
}
};
return (
{/ Your app components /}
);
}
`$3
Debug callbacks receive a
DebugMessage object:`typescript
interface DebugMessage {
timestamp: number; // Unix timestamp
level: DebugLevel; // Message level
category: string; // Component category
message: string; // Debug message text
data?: any; // Additional debug data (optional)
}
``For more details and examples, see the @phantom/browser-sdk documentation.