Overview
@drift-labs/react provides a comprehensive set of React components, hooks, and state management utilities specifically designed for building Drift Protocol applications. Built on top of @drift-labs/common, this package handles wallet connection, account subscriptions, real-time data updates, and UI components.
Installation
npm install @drift-labs/react @drift-labs/common @drift-labs/icons
Peer Dependencies
This package requires React 19 and specific versions of Solana libraries.
Quick Start
Basic Setup
Wrap your app with the DriftProvider to enable Drift functionality:
import { DriftProvider } from '@drift-labs/react' ;
import { DEFAULT_BREAKPOINTS } from '@drift-labs/react' ;
function App () {
return (
< DriftProvider
breakpoints = { DEFAULT_BREAKPOINTS }
wallets = { [] } // Optional: provide wallet adapters
>
< YourApp />
</ DriftProvider >
);
}
The DriftProvider automatically sets up wallet connection, RPC connection management, SOL balance tracking, and geo-blocking checks.
Using Hooks
Access Drift functionality through hooks:
import { useCommonDriftStore , useSolBalance } from '@drift-labs/react' ;
function WalletInfo () {
const authority = useCommonDriftStore (( s ) => s . authority );
const solBalance = useCommonDriftStore (( s ) => s . currentSolBalance );
if ( ! authority ) {
return < div > Wallet not connected </ div > ;
}
return (
< div >
< p > Address: { authority . toString () } </ p >
< p > Balance: { solBalance . value . toString () } SOL </ p >
</ div >
);
}
Core Components
DriftProvider
The main provider component that wraps your application:
import { DriftProvider } from '@drift-labs/react' ;
import type { DriftProviderProps } from '@drift-labs/react' ;
const breakpoints = {
mobile: 768 ,
tablet: 1024 ,
desktop: 1440 ,
};
function App () {
return (
< DriftProvider
breakpoints = { breakpoints }
wallets = { wallets }
disableAutoconnect = { false }
autoconnectionDelay = { 2000 }
disable = { {
idlePollingRateSwitcher: false ,
emulation: false ,
geoblocking: false ,
initConnection: false ,
subscribeSolBalance: false ,
} }
geoBlocking = { {
callback : () => {
console . log ( 'User is geo-blocked' );
},
} }
>
< YourApp />
</ DriftProvider >
);
}
You can disable individual features using the disable prop to optimize performance for specific use cases.
DriftWalletProvider
Handles Solana wallet connection (used internally by DriftProvider):
import { DriftWalletProvider } from '@drift-labs/react' ;
import { PhantomWalletAdapter , SolflareWalletAdapter } from '@solana/wallet-adapter-wallets' ;
const wallets = [
new PhantomWalletAdapter (),
new SolflareWalletAdapter (),
];
function WalletWrapper ({ children }) {
return (
< DriftWalletProvider
wallets = { wallets }
disableAutoconnect = { false }
autoconnectionDelay = { 2000 }
>
{ children }
</ DriftWalletProvider >
);
}
Essential Hooks
useCommonDriftStore
Access the global Drift application state:
import { useCommonDriftStore } from '@drift-labs/react' ;
function AccountInfo () {
const authority = useCommonDriftStore (( s ) => s . authority );
const connection = useCommonDriftStore (( s ) => s . connection );
const env = useCommonDriftStore (( s ) => s . env );
const driftClient = useCommonDriftStore (( s ) => s . driftClient . client );
// Access setter for mutations
const set = useCommonDriftStore (( s ) => s . set );
const updateSetting = () => {
set (( state ) => {
state . someSetting = newValue ;
});
};
return < div > ... </ div > ;
}
The store uses Zustand with Immer for immutable state updates. See stores/useCommonDriftStore.tsx:1 for the full state schema.
useSolBalance
Automatically tracks SOL balance for the connected wallet:
import { useSolBalance , useCommonDriftStore } from '@drift-labs/react' ;
function BalanceDisplay () {
// Hook is already called in DriftProvider, just read from store
const balance = useCommonDriftStore (( s ) => s . currentSolBalance );
return (
< div >
{ balance . loaded ? (
< span > { balance . value . toNum () } SOL </ span >
) : (
< span > Loading... </ span >
) }
</ div >
);
}
The hook subscribes to account changes via connection.onAccountChange(), providing real-time balance updates. See hooks/useSolBalance.tsx:10.
useWalletContext
Access wallet adapter context:
import { useWalletContext } from '@drift-labs/react' ;
function ConnectButton () {
const { connect , disconnect , connected , publicKey } = useWalletContext ();
return (
< button onClick = { () => connected ? disconnect () : connect () } >
{ connected ? `Disconnect ${ publicKey ?. toString (). slice ( 0 , 4 ) } ...` : 'Connect Wallet' }
</ button >
);
}
useDriftClientIsReady
Check if the Drift client is initialized and ready:
import { useDriftClientIsReady } from '@drift-labs/react' ;
function TradingInterface () {
const isReady = useDriftClientIsReady ();
if ( ! isReady ) {
return < LoadingSpinner /> ;
}
return < TradingPanel /> ;
}
useCurrentRpc
Get the current RPC endpoint:
import { useCurrentRpc } from '@drift-labs/react' ;
function RpcStatus () {
const currentRpc = useCurrentRpc ();
return < div > Connected to: { currentRpc . label } </ div > ;
}
useEmulation
Handle account emulation for testing:
import { useEmulation } from '@drift-labs/react' ;
function EmulationToggle () {
const { emulationMode , setEmulationMode } = useEmulation ();
return (
< button onClick = { () => setEmulationMode ( ! emulationMode ) } >
{ emulationMode ? 'Exit Emulation' : 'Enter Emulation' }
</ button >
);
}
useAccountExists
Check if a user account exists:
import { useAccountExists } from '@drift-labs/react' ;
function AccountStatus () {
const accountExists = useAccountExists ();
if ( accountExists === null ) {
return < div > Checking account... </ div > ;
}
return accountExists ? < Dashboard /> : < CreateAccountPrompt /> ;
}
useAccountCreationCost
Get the cost to create a new Drift account:
import { useAccountCreationCost } from '@drift-labs/react' ;
function CreateAccountButton () {
const creationCost = useAccountCreationCost ();
return (
< button >
Create Account ( { creationCost . toFixed ( 4 ) } SOL)
</ button >
);
}
Priority Fees
usePriorityFeeUserSettings
Manage user’s priority fee preferences:
import { usePriorityFeeUserSettings } from '@drift-labs/react' ;
function PriorityFeeSettings () {
const {
currentPriorityFeeMethod ,
setCurrentPriorityFeeMethod ,
currentMaxPriorityFeeCap ,
setCurrentMaxPriorityFeeCap ,
currentCustomPriorityFee ,
setCurrentCustomPriorityFee ,
} = usePriorityFeeUserSettings ();
return (
< div >
< select
value = { currentPriorityFeeMethod }
onChange = { ( e ) => setCurrentPriorityFeeMethod ( e . target . value ) }
>
< option value = "auto" > Auto </ option >
< option value = "custom" > Custom </ option >
</ select >
{ currentPriorityFeeMethod === 'custom' && (
< input
type = "number"
value = { currentCustomPriorityFee }
onChange = { ( e ) => setCurrentCustomPriorityFee ( Number ( e . target . value )) }
/>
) }
</ div >
);
}
useCurrentPriorityFee
Get the computed priority fee for transactions:
import { useCurrentPriorityFee } from '@drift-labs/react' ;
function TransactionPreview () {
const priorityFee = useCurrentPriorityFee ();
return (
< div >
< p > Priority Fee: { priorityFee } micro-lamports </ p >
</ div >
);
}
Oracle Prices
useCurrentOraclePrice
Get real-time oracle price for a market:
import { useCurrentOraclePrice } from '@drift-labs/react' ;
function MarketPrice ({ marketIndex }) {
const price = useCurrentOraclePrice ( marketIndex , 'perp' );
return < div > Current Price: $ { price ?. toFixed ( 2 ) } </ div > ;
}
useOraclePriceStore
Access the oracle price store directly:
import { useOraclePriceStore } from '@drift-labs/react' ;
function PriceMonitor () {
const perpPrices = useOraclePriceStore (( s ) => s . perpOraclePriceData );
const spotPrices = useOraclePriceStore (( s ) => s . spotOraclePriceData );
return (
< div >
{ perpPrices . map (( price , index ) => (
< div key = { index } > Market { index } : $ { price } </ div >
)) }
</ div >
);
}
Utility Hooks
Run a callback immediately and then on an interval:
import { useImmediateInterval } from '@drift-labs/react' ;
function DataRefresher () {
const [ data , setData ] = useState ( null );
useImmediateInterval (
async () => {
const newData = await fetchData ();
setData ( newData );
},
5000 // Every 5 seconds
);
return < div > { data } </ div > ;
}
useSyncLocalStorage
Sync state with localStorage:
import { useSyncLocalStorage } from '@drift-labs/react' ;
function ThemeToggle () {
const [ theme , setTheme ] = useSyncLocalStorage ( 'theme' , 'dark' );
return (
< button onClick = { () => setTheme ( theme === 'dark' ? 'light' : 'dark' ) } >
Current: { theme }
</ button >
);
}
Disable page scrolling (useful for modals):
import { useDisableScroll } from '@drift-labs/react' ;
function Modal ({ isOpen }) {
useDisableScroll ( isOpen );
if ( ! isOpen ) return null ;
return < div className = "modal" > ... </ div > ;
}
useTargetedPopover
Manage popover positioning with Floating UI:
import { useTargetedPopover } from '@drift-labs/react' ;
function Tooltip ({ children , content }) {
const {
isOpen ,
setIsOpen ,
refs ,
floatingStyles ,
} = useTargetedPopover ({
placement: 'top' ,
offset: 8 ,
});
return (
<>
< div
ref = { refs . setReference }
onMouseEnter = { () => setIsOpen ( true ) }
onMouseLeave = { () => setIsOpen ( false ) }
>
{ children }
</ div >
{ isOpen && (
< div ref = { refs . setFloating } style = { floatingStyles } >
{ content }
</ div >
) }
</>
);
}
UI Components
Table Components
Pre-built table components for displaying market data:
import {
HeaderRow ,
HeaderCell ,
BodyRow ,
BodyCell ,
} from '@drift-labs/react' ;
function MarketTable ({ markets }) {
return (
< table >
< HeaderRow >
< HeaderCell > Market </ HeaderCell >
< HeaderCell > Price </ HeaderCell >
< HeaderCell > 24h Change </ HeaderCell >
</ HeaderRow >
< tbody >
{ markets . map (( market ) => (
< BodyRow key = { market . index } >
< BodyCell > { market . symbol } </ BodyCell >
< BodyCell > $ { market . price } </ BodyCell >
< BodyCell > { market . change } % </ BodyCell >
</ BodyRow >
)) }
</ tbody >
</ table >
);
}
Loaders
Loading indicators:
import { Spinner , SkeletonLoader } from '@drift-labs/react' ;
function LoadingState () {
return (
< div >
< Spinner size = "large" />
< SkeletonLoader width = { 200 } height = { 20 } />
</ div >
);
}
Select Components
Customizable select inputs:
import { Select } from '@drift-labs/react' ;
function MarketSelector ({ markets , value , onChange }) {
return (
< Select
value = { value }
onChange = { onChange }
options = { markets . map (( m ) => ({
value: m . index ,
label: m . symbol ,
})) }
/>
);
}
Charts
useGroupHistoricalPricesByAverage
Group historical price data for charting:
import { useGroupHistoricalPricesByAverage } from '@drift-labs/react' ;
function PriceChart ({ prices }) {
const groupedData = useGroupHistoricalPricesByAverage ( prices , '1h' );
return < LineChart data = { groupedData } /> ;
}
Store Management
useCommonDriftStore
The main application store built with Zustand:
import { useCommonDriftStore } from '@drift-labs/react' ;
// Read state
const authority = useCommonDriftStore (( s ) => s . authority );
const connection = useCommonDriftStore (( s ) => s . connection );
// Update state
const set = useCommonDriftStore (( s ) => s . set );
set (( state ) => {
state . someValue = newValue ;
});
// Get entire state (use sparingly)
const get = useCommonDriftStore (( s ) => s . get );
const fullState = get ();
useScreenSizeStore
Responsive design utilities:
import { useScreenSizeStore } from '@drift-labs/react' ;
function ResponsiveComponent () {
const isMobile = useScreenSizeStore (( s ) => s . isMobile );
const isTablet = useScreenSizeStore (( s ) => s . isTablet );
const isDesktop = useScreenSizeStore (( s ) => s . isDesktop );
if ( isMobile ) return < MobileView /> ;
if ( isTablet ) return < TabletView /> ;
return < DesktopView /> ;
}
Advanced Patterns
Custom RPC Management
import { useCommonDriftStore , useHandleBadRpc } from '@drift-labs/react' ;
function RpcSwitcher () {
const currentRpc = useCommonDriftStore (( s ) => s . rpc );
const set = useCommonDriftStore (( s ) => s . set );
useHandleBadRpc (); // Automatically switch on errors
const switchRpc = ( newRpc ) => {
set (( state ) => {
state . rpc = newRpc ;
});
};
return < RpcSelector current = { currentRpc } onSwitch = { switchRpc } /> ;
}
Geo-blocking
import { useGeoBlocking } from '@drift-labs/react' ;
function App () {
const isBlocked = useGeoBlocking (() => {
console . log ( 'User is geo-blocked' );
// Redirect or show message
});
if ( isBlocked ) {
return < div > Service not available in your region </ div > ;
}
return < MainApp /> ;
}
Package Structure
react/
├── src/
│ ├── actions/ # Action creators
│ ├── components/ # UI components
│ ├── constants/ # Constants and configs
│ ├── hooks/ # React hooks
│ ├── providers/ # Context providers
│ ├── stores/ # Zustand stores
│ ├── utils/ # Utility functions
│ └── index.ts # Main export
├── lib/ # Compiled output
├── package.json
└── tsconfig.json
Best Practices
Use useCommonDriftStore selectors to avoid unnecessary re-renders
Only select the specific state slices you need
Use set with Immer for state mutations
Always check authority before making transactions
Handle disconnection gracefully
Use useWalletContext for wallet adapter methods
Common Package Core utilities used by this package
Icons Package Icon components for your UI
GitHub Repository View source code
API Reference Complete API documentation