Skip to main content

React Integration

Complete guide for integrating Oko into React applications. @oko-wallet/oko-sdk-react provides ready-to-use hooks — no manual context setup needed.

Get started faster

Prefer a ready-to-run example? Try the Cosmos + EVM + SVM (React) starter template.

Installation

npm install @oko-wallet/oko-sdk-react

All chain SDKs (EVM, Cosmos, Solana) are included as dependencies.

Provider Setup

Wrap your app with OkoProvider. Only configured chains are initialized — unused ones are never bundled.

import { OkoProvider } from "@oko-wallet/oko-sdk-react";

const okoConfig = {
apiKey: "YOUR_API_KEY",
theme: "dark" as const,
eth: true,
cosmos: true,
svm: { chainId: "solana:mainnet" },
};

export default function App({ children }: { children: React.ReactNode }) {
return <OkoProvider config={okoConfig}>{children}</OkoProvider>;
}

OkoProviderConfig

PropertyTypeRequiredDescription
apiKeystringYesYour Oko API key
sdkEndpointstringNoCustom SDK endpoint URL
theme"light" | "dark"NoInitial theme for the wallet UI
ethboolean | OkoEthConfigNoEnable Ethereum/EVM chain support
cosmosboolean | OkoCosmosConfigNoEnable Cosmos chain support
svmboolean | OkoSvmConfigNoEnable Solana/SVM support (true defaults to solana:mainnet)

useOko

Core hook for authentication and wallet state.

import { useOko } from "@oko-wallet/oko-sdk-react";

function ConnectButton() {
const { isReady, isSignedIn, signOut, openSignInModal, email, name } = useOko();

if (!isReady) {
return <p>Loading...</p>;
}

if (isSignedIn) {
return (
<div>
<p>Signed in as {email}</p>
<button onClick={signOut}>Sign Out</button>
</div>
);
}

return <button onClick={openSignInModal}>Sign In</button>;
}

Return Values

PropertyTypeDescription
walletOkoWalletInterface | nullRaw SDK instance for advanced usage
isReadybooleanSDK fully initialized and usable
isSignedInbooleanUser is authenticated
authTypeAuthType | nullAuth provider ("google", "x", "discord", etc.)
emailstring | nullUser email
namestring | nullUser display name
publicKeystring | nullsecp256k1 public key
signIn(type: SignInType) => Promise<void>Start sign-in flow
signOut() => Promise<void>Sign out current user
openSignInModal() => Promise<void>Open built-in provider picker UI
setTheme(theme: OkoWalletTheme) => Promise<void>Update the wallet theme

SignInType

Supported providers: "google", "email", "x", "telegram", "discord", "github"

Chain Hooks

Chain hooks are imported from subpath exports. Each returns the chain SDK instance and initialization status.

useOkoEth

import { useOkoEth } from "@oko-wallet/oko-sdk-react/eth";

function EthPanel() {
const { ethWallet, isReady, address } = useOkoEth();

if (!isReady || !ethWallet) return null;

return <p>ETH Address: {address}</p>;
}
PropertyTypeDescription
ethWalletOkoEthWalletInterface | nullETH SDK instance
isInitializedbooleaninit() succeeded
isReadybooleanFully initialized and usable
addressstring | nullEVM address (0x...), same across all EVM chains

useOkoCosmos

import { useOkoCosmos } from "@oko-wallet/oko-sdk-react/cosmos";

function CosmosPanel() {
const { cosmosWallet, isReady } = useOkoCosmos();

if (!isReady || !cosmosWallet) return null;

const signer = cosmosWallet.getOfflineSigner("cosmoshub-4");
}
PropertyTypeDescription
cosmosWalletOkoCosmosWalletInterface | nullCosmos SDK instance
isInitializedbooleaninit() succeeded
isReadybooleanFully initialized and usable

useCosmosAddress

Cosmos addresses vary by chain (different bech32 prefixes), so use this hook with a specific chain ID.

import { useCosmosAddress } from "@oko-wallet/oko-sdk-react/cosmos";

function CosmosAddress() {
const { address, isLoading } = useCosmosAddress("cosmoshub-4");

if (isLoading) return <p>Loading...</p>;

return <p>Cosmos Address: {address}</p>;
}
PropertyTypeDescription
addressstring | nullBech32 address for the given chain (e.g. cosmos1..., osmo1...)
isLoadingbooleanAddress is being resolved

useOkoSvm

import { useOkoSvm } from "@oko-wallet/oko-sdk-react/svm";

function SolanaPanel() {
const { svmWallet, isReady, address } = useOkoSvm();

if (!isReady || !svmWallet) return null;

return <p>Solana Address: {address}</p>;
}
PropertyTypeDescription
svmWalletOkoSvmWalletInterface | nullSVM SDK instance
isInitializedbooleaninit() succeeded
isReadybooleanFully initialized and usable
addressstring | nullSolana base58 address, same across all Solana clusters

Components

Connect Button

// components/ConnectWalletButton.tsx
import { useOko } from "@oko-wallet/oko-sdk-react";

export const ConnectWalletButton = () => {
const { isReady, isSignedIn, openSignInModal, signOut } = useOko();

if (!isReady) {
return null;
}

if (isSignedIn) {
return (
<button onClick={signOut} className="px-4 py-2 bg-gray-500 text-white rounded">
Disconnect
</button>
);
}

return (
<button onClick={openSignInModal} className="px-4 py-2 bg-red-500 text-white rounded">
Connect
</button>
);
};

Transaction Widget

// components/TransactionWidget.tsx
import { useState } from "react";
import { useOkoEth } from "@oko-wallet/oko-sdk-react/eth";

export const TransactionWidget = () => {
const { ethWallet, isReady } = useOkoEth();
const [recipient, setRecipient] = useState("");
const [amount, setAmount] = useState("");

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();

if (!ethWallet || !isReady) {
return;
}

try {
const provider = await ethWallet.getEthereumProvider();

await provider.request({
method: "eth_sendTransaction",
params: [{
to: recipient,
value: `0x${parseInt(amount).toString(16)}`,
gas: "0x5208",
}],
});
setRecipient("");
setAmount("");
} catch (err) {
console.error("Transaction failed:", err);
}
};

return (
<form onSubmit={handleSubmit} className="space-y-4">
<input
type="text"
value={recipient}
onChange={(e) => setRecipient(e.target.value)}
placeholder="Recipient address"
className="w-full border rounded px-3 py-2"
required
/>
<input
type="number"
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="Amount (ETH)"
step="0.001"
className="w-full border rounded px-3 py-2"
required
/>
<button
type="submit"
className="w-full px-4 py-2 bg-green-500 text-white rounded"
>
Send Transaction
</button>
</form>
);
};

Full Example

import { OkoProvider, useOko } from "@oko-wallet/oko-sdk-react";
import { useOkoEth } from "@oko-wallet/oko-sdk-react/eth";
import { useCosmosAddress } from "@oko-wallet/oko-sdk-react/cosmos";
import { useOkoSvm } from "@oko-wallet/oko-sdk-react/svm";

function Wallet() {
const { isReady, isSignedIn, signOut, openSignInModal, email, name } = useOko();
const { address: ethAddress } = useOkoEth();
const { address: cosmosAddress } = useCosmosAddress("cosmoshub-4");
const { address: svmAddress } = useOkoSvm();

if (!isReady) return <p>Initializing...</p>;

if (!isSignedIn) {
return <button onClick={openSignInModal}>Sign In</button>;
}

return (
<div>
<p>Welcome, {name || email}</p>
<p>ETH: {ethAddress}</p>
<p>Cosmos: {cosmosAddress}</p>
<p>Solana: {svmAddress}</p>
<button onClick={signOut}>Sign Out</button>
</div>
);
}

export default function App() {
return (
<OkoProvider
config={{
apiKey: "your-api-key",
eth: true,
cosmos: true,
svm: { chainId: "solana:mainnet" },
}}
>
<Wallet />
</OkoProvider>
);
}

Runtime Theme Switching

If your app supports dark mode, sync the theme with Oko at runtime using the setTheme function from the useOko hook:

// hooks/useThemeSync.ts
import { useEffect } from "react";
import { useOko } from "@oko-wallet/oko-sdk-react";

export function useThemeSync(theme: "light" | "dark") {
const { isReady, setTheme } = useOko();

useEffect(() => {
if (!isReady) return;
setTheme(theme);
}, [theme, isReady, setTheme]);
}

Next Steps