Guide wallet connection and frontend transaction submission in React using @aptos-labs/wallet-adapter-react. End
users sign transactions via their browser wallet (Petra, Nightly, etc.) — never via raw private keys.
@aptos-labs/wallet-adapter-react for frontend wallet integration — this is the standard React adapter.AptosWalletAdapterProvider — all useWallet() calls require this context.useWallet() hook to access wallet functions in React components.signAndSubmitTransaction (from useWallet()) in frontend — NOT the SDK's direct
aptos.signAndSubmitTransaction.aptos.waitForTransaction({ transactionHash }) after submit — the wallet returns when the tx is
accepted, not committed.Account.generate() or raw private keys in browser/frontend — use wallet adapter for end users.aptos.signAndSubmitTransaction in React components — use the wallet adapter's version from
useWallet().wallets array from useWallet() for a dynamic list.bash
npm install @aptos-labs/wallet-adapter-react
Modern AIP-62 standard wallets (Petra, Nightly, etc.) are autodetected and do NOT require additional packages. Legacy wallets need their plugin package installed separately.
Wrap your app root with AptosWalletAdapterProvider:
tsx
// main.tsx or App.tsx
import { AptosWalletAdapterProvider } from "@aptos-labs/wallet-adapter-react";
import { Network } from "@aptos-labs/ts-sdk";
function App() {
return (
<AptosWalletAdapterProvider
autoConnect={true}
dappConfig={{
network: Network.TESTNET
}}
onError={(error) => console.error("Wallet error:", error)}
>
<YourApp />
</AptosWalletAdapterProvider>
);
}
tsx
import { useWallet } from "@aptos-labs/wallet-adapter-react";
function MyComponent() {
const {
account, // Current connected account { address, publicKey }
connected, // Boolean: is wallet connected?
wallet, // Current wallet info { name, icon, url }
wallets, // Array of available wallets
connect, // (walletName) => Promise<void>
disconnect, // () => Promise<void>
signAndSubmitTransaction, // Submit entry function calls (use THIS in frontend)
signTransaction, // Sign without submitting
submitTransaction, // Submit a signed transaction
signMessage, // Sign an arbitrary message
signMessageAndVerify, // Sign and verify a message
changeNetwork, // Switch networks (not all wallets support this)
network // Current network info
} = useWallet();
}
Use typed payloads with InputTransactionData:
tsx
// entry-functions/increment.ts
import { InputTransactionData } from "@aptos-labs/wallet-adapter-react";
import { MODULE_ADDRESS } from "../lib/aptos";
export function buildIncrementPayload(): InputTransactionData {
return {
data: {
function: `${MODULE_ADDRESS}::counter::increment`,
functionArguments: []
}
};
}
tsx
// components/IncrementButton.tsx
import { useWallet } from "@aptos-labs/wallet-adapter-react";
import { aptos } from "../lib/aptos";
import { buildIncrementPayload } from "../entry-functions/increment";
function IncrementButton() {
const { signAndSubmitTransaction } = useWallet();
const handleClick = async () => {
try {
const response = await signAndSubmitTransaction(buildIncrementPayload());
await aptos.waitForTransaction({
transactionHash: response.hash
});
} catch (error) {
console.error("Transaction failed:", error);
}
};
return <button onClick={handleClick}>Increment</button>;
}
tsx
import { useWallet } from "@aptos-labs/wallet-adapter-react";
function WalletInfo() {
const { account, connected, connect, disconnect, wallet, wallets } = useWallet();
if (!connected) {
return (
<div>
{wallets.map((w) => (
<button key={w.name} onClick={() => connect(w.name)}>
Connect {w.name}
</button>
))}
</div>
);
}
return (
<div>
<p>Connected: {account?.address}</p>
<p>Wallet: {wallet?.name}</p>
<button onClick={disconnect}>Disconnect</button>
</div>
);
}
MistakeCorrect approachMissing AptosWalletAdapterProvider wrapperWrap app root with the providerNot waiting for transaction after submitAlways call aptos.waitForTransaction()Using SDK aptos.signAndSubmitTransaction in ReactUse the wallet adapter's signAndSubmitTransaction from useWallet()Using Account.generate() in frontendUse wallet adapter; generate only in server/scriptsNot handling user rejectionCatch and check for rejection-related error messagesHardcoding wallet namesUse wallets array from useWallet() for dynamic list