> ## Documentation Index
> Fetch the complete documentation index at: https://digraphsas-docs-cli.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Velora Widget Next.js example

> End-to-end widget integration for the Next.js app router, with a client-only mount and a /swap route.

A Next.js 14+ app-router integration that mounts the Velora Widget at `/swap`. The widget reads `window` and `localStorage` on mount, so it must be client-only. We use `next/dynamic` with `ssr: false`.

## File tree

```text theme={null}
my-app/
├─ package.json
├─ next.config.js
└─ src/app/
   ├─ layout.tsx
   ├─ page.tsx
   └─ swap/
      ├─ page.tsx
      └─ widget.tsx
```

## Install

<CodeGroup>
  ```bash pnpm theme={null}
  pnpm create next-app@latest my-app --typescript --app
  cd my-app
  pnpm add @velora-dex/widget @tanstack/react-query
  ```

  ```bash npm theme={null}
  npx create-next-app@latest my-app --typescript --app
  cd my-app
  npm install @velora-dex/widget @tanstack/react-query
  ```

  ```bash yarn theme={null}
  yarn create next-app my-app --typescript --app
  cd my-app
  yarn add @velora-dex/widget @tanstack/react-query
  ```
</CodeGroup>

## `src/app/layout.tsx`

```tsx theme={null}
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}
```

## `src/app/swap/widget.tsx`

The widget itself, wrapped in `dynamic(... { ssr: false })`.

```tsx theme={null}
"use client";

import dynamic from "next/dynamic";

const Widget = dynamic(
  () => import("@velora-dex/widget").then((m) => ({ default: m.Widget })),
  { ssr: false, loading: () => <div>Loading widget…</div> }
);

export default function ClientWidget() {
  return (
    <Widget
      config={{
        theme: "light",
        partnerConfig: {
          partner: process.env.NEXT_PUBLIC_PARTNER_KEY,
        },
      }}
    />
  );
}
```

## `src/app/swap/page.tsx`

```tsx theme={null}
import ClientWidget from "./widget";

export default function SwapPage() {
  return (
    <main style={{ display: "flex", justifyContent: "center", padding: "2rem" }}>
      <ClientWidget />
    </main>
  );
}
```

## `.env.local`

```env theme={null}
NEXT_PUBLIC_PARTNER_KEY=my-app-name
```

Restart `next dev` after creating or changing `.env.local`.

## Run it

```bash theme={null}
pnpm dev
```

Visit [http://localhost:3000/swap](http://localhost:3000/swap). You should see the widget render with **Connect Wallet** in the header.

## Why `ssr: false`?

The widget reads `window`, `localStorage`, and `prefers-color-scheme` on mount. None of those exist during server rendering. `dynamic(... { ssr: false })` defers the import to the browser, so the widget only ever runs client-side.

If you forget `ssr: false`, you'll see a hydration-mismatch error or a `window is not defined` exception.

## With dApp-mode wallet

If your app already manages the wallet (wagmi, RainbowKit, or any other host-side wallet library), switch to dApp mode and pass the provider:

```tsx theme={null}
"use client";

import dynamic from "next/dynamic";
import { useConnection, useWalletClient } from "wagmi";

const Widget = dynamic(
  () => import("@velora-dex/widget").then((m) => ({ default: m.Widget })),
  { ssr: false }
);

export default function ClientWidget() {
  const { connector } = useConnection();
  const { data: walletClient } = useWalletClient();

  // Hand the EIP-1193 provider to the widget once a wallet is connected.
  const provider = walletClient?.transport;

  return (
    <Widget
      config={{
        widgetMode: "dapp",
        excludeUI: ["wallet-management"],
      }}
      provider={provider}
      events={{
        onConnectWalletClick: () => {
          // host-app wallet modal
          openConnectModal();
        },
      }}
    />
  );
}
```

See [Wallet management](/widget/wallet-management) for the full pattern.

## Related pages

* [Install](/widget/install) — package install and basic setup.
* [Wallet management](/widget/wallet-management) — standalone vs dApp mode.
* [Compatibility](/widget/compatibility) — full SSR notes.
* [React example](/widget/examples/react) — same widget on a Vite stack.
