Skip to content
wyllet
  • Docs
  • Features
  • Playground
  • Blog
  • Docs
  • Features
  • Playground
  • Blog
  • Compare
  • Changelog
GitHub @wylletdevnpm Support
esc
  • IntroductionWhat Wyllet is, what it includes, and how it fits into a wagmi + viem dApp.
  • InstallationInstall Wyllet and its peer dependencies, and enable WalletConnect.
  • Quick startAdd a working connect button to a React dApp in a few minutes.
  • Next.jsUse Wyllet with the Next.js App Router, server components and SSR.
  • Build with AI assistantsGive Cursor, Claude Code, Copilot or ChatGPT the Wyllet docs and the rules for a correct integration.
  • ConfigurationCreate a wagmi config with getDefaultConfig: app info, chains, transports and wallets.
  • WylletProviderEvery WylletProvider prop: theme, appearance, tokens, auth, messages and callbacks.
  • WylletButtonThe Island button, its display options, and building your own trigger with useWylletButton.
Overview

Getting started

  • Introduction
  • Installation
  • Quick start
  • Next.js
  • Build with AI assistants

Core concepts

  • Configuration
  • WylletProvider
  • WylletButton
  • Presentations

Customization

  • Theming
  • Class names
  • Translations

Wallets

  • Wallets
  • All wallets
  • WalletConnect

Chains and tokens

  • Chains
  • Tokens

Features

  • Account panel
  • Activity and transactions
  • Toasts
  • Sign-In With Ethereum
  • ConnectGate

Reference

  • Hooks
  • Components
  • Utilities and types

Guides

  • Security
  • Migrate from RainbowKit
  • FAQ
wyllet

The open-source wallet connector for React dApps. Built on wagmi and viem.

MIT licensed. v1.1.0 on npm with provenance.

Product

  • Features
  • Compare
  • Playground
  • Changelog
  • Blog

Docs

  • Quick start
  • Next.js
  • Build with AI
  • Theming
  • Migrate from RainbowKit

Community

  • GitHub
  • X @wylletdev
  • npm
  • Releases
  • Report an issue

Support

  • support@wyllet.dev
  • FAQ
  • Security
  • Report a vulnerability
  • MIT License

For AI agents

  • llms.txt
  • llms-full.txt
  • RSS feed
  • Sitemap

Wallet, network and token names and logos are trademarks of their respective owners and are used only to identify them.

Docs/Getting started

Next.js

Use Wyllet with the Next.js App Router, server components and SSR.

View .mdReport a problem

Wyllet works with the Next.js App Router. You put the providers in a client component, wrap your layout with it, and render the button from any page.

How it works with server components

The published package starts with a 'use client' directive, so every Wyllet export is a client module. In practice this means:

  • You can render <WylletButton /> and <ConnectGate> from a server component. They become client components automatically.
  • Functions such as getDefaultConfig(), obsidianTheme() or withDefaultTokens() must be called from client modules, such as the providers file below. A server component cannot call functions exported from a client module.
  • The providers themselves (WagmiProvider, QueryClientProvider, WylletProvider) need a client component, because they hold state.

1. Add the project ID

Store the WalletConnect project ID in an environment variable with the NEXT_PUBLIC_ prefix so it is available in the browser.

.env.local
NEXT_PUBLIC_WC_PROJECT_ID=your_project_id

2. Create the config

lib/wagmi.ts
import { base, mainnet } from 'viem/chains'
import { getDefaultConfig } from 'wyllet'
 
export const config = getDefaultConfig({
  appName: 'My dApp',
  appUrl: 'https://my-dapp.xyz',
  walletConnectProjectId: process.env.NEXT_PUBLIC_WC_PROJECT_ID,
  chains: [mainnet, base],
  ssr: true,
})

appUrl defaults to window.location.origin. On the server there is no window, so set appUrl explicitly when the config is also evaluated during server rendering. The URL is sent to wallets as part of the WalletConnect metadata.

ssr: true is a regular wagmi option. getDefaultConfig() accepts every wagmi createConfig() parameter except chains, transports and connectors (which it builds for you) and passes them through. That includes options such as ssr and storage.

3. Create a providers component

app/providers.tsx
'use client'
 
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { useState, type ReactNode } from 'react'
import { WagmiProvider } from 'wagmi'
import { WylletProvider } from 'wyllet'
import { config } from '@/lib/wagmi'
 
export function Providers({ children }: { children: ReactNode }) {
  const [queryClient] = useState(() => new QueryClient())
 
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        <WylletProvider>{children}</WylletProvider>
      </QueryClientProvider>
    </WagmiProvider>
  )
}

Creating the QueryClient inside useState keeps one client per browser session and avoids sharing a client between server requests.

4. Wrap the root layout

app/layout.tsx
import type { ReactNode } from 'react'
import { Providers } from './providers'
 
export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  )
}

5. Render the button

app/page.tsx
import { WylletButton } from 'wyllet'
 
export default function Page() {
  return (
    <header>
      <WylletButton />
    </header>
  )
}

This page stays a server component. Pass theme objects, appearance options and other non-serializable props on <WylletProvider> in providers.tsx, not from server components.

Hydration and SSR

Wallet state only exists in the browser, so Wyllet avoids rendering account details on the server:

  • <WylletButton> renders a hidden, disabled placeholder until it has mounted on the client. The placeholder keeps its space in the layout, so nothing shifts when the real button appears.
  • <ConnectGate> never renders its children before mount. Until then it shows its default prompt hidden, or your fallback if you passed one.
  • The panel and toasts render into a portal only on the client.

If you build your own button with useWylletButton(), use its mounted flag the same way:

components/connect-button.tsx
'use client'
 
import { useWylletButton } from 'wyllet'
 
export function ConnectButton() {
  const { mounted, account, open } = useWylletButton()
 
  if (!mounted) return <button disabled aria-hidden style={{ visibility: 'hidden' }}>Connect</button>
 
  return (
    <button onClick={(e) => open(e.currentTarget)}>
      {account ? account.displayName : 'Connect'}
    </button>
  )
}

See WylletButton for the full shape of useWylletButton().

Light and dark mode

With the default theme pair, Wyllet follows the operating system through prefers-color-scheme. If your site has its own theme toggle, pass the current mode as colorMode from your providers component so Wyllet matches it:

<WylletProvider colorMode={siteTheme}>{children}</WylletProvider>

siteTheme here is your own 'light', 'dark' or 'auto' value. See Theming.

Related

  • Configuration
  • WylletProvider
  • WalletConnect
PreviousQuick startNextBuild with AI assistants

On this page

  • How it works with server components
  • 1. Add the project ID
  • 2. Create the config
  • 3. Create a providers component
  • 4. Wrap the root layout
  • 5. Render the button
  • Hydration and SSR
  • Light and dark mode
  • Related