Skip to content

Wallet UI Kit

The Wallet UI Kit gives you prebuilt React UI for ZeroDev Wallet. Use it when you want to get started faster with a ready-made login flow instead of building every authentication screen yourself.

The kit uses a Wagmi-compatible ZeroDev connector, so after the user signs in you can use standard Wagmi hooks such as useAccount, useSignMessage, and useSendTransaction.

The current kit covers login and an experimental confirmation screen for signature signing and transaction confirmations that is currently in beta. This confirmation UI will improve over time. More wallet UI components are coming, including onramps, asset management and portfolio views, transaction history, and chain-abstracted balances.

For a fully custom UI, use the hook-based authentication pages instead: Passkeys, Email OTP, Magic Link, or Google OAuth.

Before you start

In the ZeroDev Dashboard, make sure your project has:

  • The app origin added to the project's ACL allowlist, such as http://localhost:3000 for local development.
  • The auth methods you plan to show in the UI Kit configured for the project.
  • At least one enabled network.

This guide uses Arbitrum Sepolia and email OTP. Replace the chain, chain RPC URL, and enabled auth methods for your app.

Install packages

npm
npm i @zerodev/react-wallet-ui @zerodev/wallet-react @zerodev/wallet-core wagmi viem @tanstack/react-query

Configure Wagmi

Import zeroDevWallet from @zerodev/react-wallet-ui. This connector wraps the base ZeroDev Wallet connector and controls the kit's auth UI state.

import { zeroDevWallet } from '@zerodev/react-wallet-ui'
import { createConfig, http } from 'wagmi'
import { arbitrumSepolia } from 'wagmi/chains'
 
const projectId = '<your-project-id>'
const chainRpcUrl = 'https://sepolia-rollup.arbitrum.io/rpc'
 
export const config = createConfig({
  chains: [arbitrumSepolia],
  connectors: [
    zeroDevWallet({
      projectId,
      chains: [arbitrumSepolia],
      mode: '7702',
      config: {
        auth: {
          enabledMethods: ['email', 'google', 'passkey'],
          emailAuthMethod: 'otp',
        },
      },
    }),
  ],
  transports: {
    [arbitrumSepolia.id]: http(chainRpcUrl),
  },
})

Only include auth methods that are enabled for your project. This example uses OTP for email authentication; use the hook-based Magic Link guide if you want to build a magic-link flow yourself.

Add providers and styles

Import the kit stylesheet once at your app entry, then wrap your app with Wagmi and TanStack Query providers.

import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import '@zerodev/react-wallet-ui/styles.css'
import type { ReactNode } from 'react'
import { WagmiProvider } from 'wagmi'
import { config } from './wagmi'
 
const queryClient = new QueryClient()
 
export function WalletProviders({ children }: { children: ReactNode }) {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        {children}
      </QueryClientProvider>
    </WagmiProvider>
  )
}

Render the login flow

Call Wagmi's connect with the ZeroDev connector to start login. Render <AuthFlow /> in the same provider tree; it displays the active auth screen while the connector waits for the user to finish authentication.

import { AuthFlow } from '@zerodev/react-wallet-ui'
import { useAccount, useConnect, useDisconnect } from 'wagmi'
 
export function WalletLogin() {
  const { address, isConnected } = useAccount()
  const { connect, connectors, isPending } = useConnect()
  const { disconnect } = useDisconnect()
  const zeroDevConnector = connectors.find(
    (connector) => connector.id === 'zerodev-wallet',
  )
 
  return (
    <div>
      {isConnected ? (
        <div>
          <p>Connected: {address}</p>
          <button type="button" onClick={() => disconnect()}>
            Disconnect
          </button>
        </div>
      ) : (
        <button
          type="button"
          disabled={!zeroDevConnector || isPending}
          onClick={() =>
            zeroDevConnector && connect({ connector: zeroDevConnector })
          }
        >
          {isPending ? 'Opening login...' : 'Connect wallet'}
        </button>
      )}
 
      <AuthPanel />
    </div>
  )
}
 
function AuthPanel() {
  return (
    <div
      style={{
        width: '100%',
        maxWidth: 500,
        height: 800,
        maxHeight: '100vh',
        margin: '0 auto',
      }}
    >
      <AuthFlow />
    </div>
  )
}

Size the container

AuthFlow renders into the space you give it. Put it in a constrained wallet-sized container, modal, or drawer instead of letting it stretch across the full page on large screens.

<div
  style={{
    width: '100%',
    maxWidth: 500,
    height: 800,
    maxHeight: '100vh',
    margin: '0 auto',
  }}
>
  <AuthFlow onClose={() => setLoginOpen(false)} />
</div>

The onClose prop is optional. Use it when your app owns surrounding UI state, such as closing a modal after the user clicks the kit's close button.

Avoid global CSS conflicts

Import the kit stylesheet once, and make sure your app's global CSS does not broadly restyle elements such as button, input, h1, or p. If your app has global element styles, scope them to your own app shell so they do not override the Wallet UI Kit screens.

Add beta signing confirmations

The UI Kit also includes SignatureRequest, an experimental confirmation screen for signature signing and transaction requests that is currently in beta. Mount it once in the same provider tree as your wallet UI.

import { AuthFlow, SignatureRequest } from '@zerodev/react-wallet-ui'
 
export function WalletOverlays() {
  return (
    <>
      <div
        style={{
          width: '100%',
          maxWidth: 500,
          height: 800,
          maxHeight: '100vh',
          margin: '0 auto',
        }}
      >
        <AuthFlow />
      </div>
 
      <SignatureRequest
        style={{
          width: '100%',
          maxWidth: 400,
          height: 600,
          maxHeight: '100vh',
        }}
      />
    </>
  )
}

By default, the kit prompts for methods such as personal_sign, eth_signTypedData_v4, eth_sendTransaction, wallet_sendTransaction, and wallet_sendCalls. This confirmation feature is experimental, in beta, and will continue improving over time.

If you only want the prebuilt login UI, you can omit SignatureRequest. To force signing and transaction requests to run in the background even if a confirmation listener is mounted later, set signing to background in the connector config:

zeroDevWallet({
  projectId,
  chains: [arbitrumSepolia],
  mode: '7702',
  config: {
    auth: {
      enabledMethods: ['email', 'google', 'passkey'],
      emailAuthMethod: 'otp',
    },
    signing: {
      mode: 'background',
    },
  },
})

Coming soon

The Wallet UI Kit will add more prebuilt wallet components and screens over time, including onramps, asset management and portfolio views, transaction history, and chain-abstracted balances. To request early access, reach out to the ZeroDev sales team.

Next steps