1. Bootstrapping Next.js frontend project

NextJS App Router (Typescript) + TailwindCSS + Shadcn UI

Next.js Pages/App Router is a full-stack React framework. The framework is flexible and helps you build large or small React applications. To start creating a new Next.js project, run the following command in the terminal:

npx create-next-app@latest my-app --typescript --tailwind --eslint

You will see the following prompts in the terminal:

What is your project named? my-app
Would you like to use TypeScript? No / Yes
Would you like to use ESLint? No / Yes
Would you like to use Tailwind CSS? No / Yes
Would you like to use `src/` directory? No / Yes
Would you like to use App Router? (recommended) No / Yes
Would you like to customize the default import alias (@/*)? No / Yes
What import alias would you like configured? @/*

For each prompt, you will choose the following options:

What is your project named? my-app
Would you like to use TypeScript? Yes # Typescript is currently the top choice
Would you like to use ESLint? Yes # ESLint to lint your code
Would you like to use Tailwind CSS? Yes # Tailwind CSS for writing interfaces quickly
Would you like to use `src/` directory? No # Do not use src directory because it is not necessary
Would you like to use App Router? (recommended) Yes # Use App router to take advantage of the latest nextjs features
Would you like to customize the default import alias (@/*)? No # No, use default

Visit Next.JS Docs here if you have problems: https://nextjs.org/docs

cd into your directory (my-app or whichever name you chose) and run the following command to install Shadcn UI

npx shadcn-ui@latest init

You will see the following prompts to set up components.json:

Which style would you like to use? › Default
Which color would you like to use as base color? › Slate
Do you want to use CSS variables for colors? › no / yes

You can choose according to your preferences, but for this bootcamp you will choose:

Which style would you like to use? › Default
Which color would you like to use as base color? › Slate
Do you want to use CSS variables for colors? › yes

Learn more with ShadcnUI's tutorial: https://ui.shadcn.com/docs/installation/next

A special feature of Shadcn UI is that the library will create a components folder directly in the project as below:

.
└── components
    ├── ui
    │   ├── button.tsx
    │   ├── input.tsx
    │   ├── card.tsx
    │   └── form.tsx  
    └── authentication-menu.tsx

You will use the components in the ui folder to build your own custom components. For example above, you use 4 components button.tsx, input.tsx, card.tsx and form.tsx to create a custom component authentication-menu.tsx.

2. Create project on WalletConnect

Visit https://cloud.walletconnect.com/sign-in.

Create an account and follow the instructions on the Dashboard to set up a Project ID.

WalletConnect will use your Project ID to track connection requests.

Wagmi + Rainbowkit + Tanstack React Query

Wagmi is a React Hook library for building interfaces more quickly. In particular, Wagmi also provides convenient React Hooks to be able to manage the entire lifecycle of a transaction, basically from connecting the wallet, to initiating the transaction, to waiting for results from the node to return and process. error handling or successful transaction status. Managing the entire lifecycle of a transaction well will help increase user experience, helping them understand their own activities.

You will install the wagmi library in common with Rainbowkit

npm install @rainbow-me/rainbowkit wagmi viem@2.x @tanstack/react-query

Next, you create the providers.tsx file in the app directory

'use client';

import * as React from 'react';
import {
  RainbowKitProvider,
  getDefaultWallets,
  getDefaultConfig,
} from '@rainbow-me/rainbowkit';
import {
  trustWallet,
  ledgerWallet,
} from '@rainbow-me/rainbowkit/wallets';
import {
  klaytn, // import klaytn mainnet
  klaytnBaobab, // import klaytn testnet
} from 'wagmi/chains';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { WagmiProvider, http } from 'wagmi';
// import according to docs

const { wallets } = getDefaultWallets();
// initialize and destructure wallets object

const config = getDefaultConfig({
  appName: 'MY_APP', // Name your app
  projectId: "WALLETCONNECT_PROJECT_ID", // Enter your WalletConnect Project ID here
  wallets: [
    ...wallets,
    {
      groupName: 'Other',
      wallets: [trustWallet, ledgerWallet],
    },
  ],
  chains: [
    klaytn,
    klaytnBaobab
  ],
  transports: {
    [klaytn.id]: http('https://rpc.ankr.com/klaytn'), // Select RPC provider Ankr instead of the default
    [klaytnBaobab.id]: http('https://rpc.ankr.com/klaytn_testnet'), // Select RPC provider Ankr instead of the default
  },
  ssr: true, // Because it is Nextjs's App router, you need to declare ssr as true
});

const queryClient = new QueryClient();

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        <RainbowKitProvider>
          {children}
        </RainbowKitProvider>
      </QueryClientProvider>
    </WagmiProvider>
  );
}

Next, add this code to the next.config.mjs file:

/** @type {import('next').NextConfig} */
const nextConfig = {
  ...
  reactStrictMode: true,
  webpack: config => {
    config.externals.push('pino-pretty', 'lokijs', 'encoding');
    return config;
  },
};

export default nextConfig;

Next, wrap <Providers> around children in your layout.tsx file to this:

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import '@rainbow-me/rainbowkit/styles.css';
import { Providers } from './providers';

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Klaytn DApp Bootcamp Frontends",
  description: "Interactive frontend for Klaytn DApp bootcamp contracts",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <Providers>
          {children}
        </Providers>
      </body>
    </html>
  );
}

3. Connect Wallet Button

You can then import <ConnectButton /> into your app

import { ConnectButton } from '@rainbow-me/rainbowkit';

export default function Home() {

  return (
    <div className="flex flex-col gap-8 items-center justify-center py-12 px-4 p-48:lg">
      <ConnectButton />
    </div>
  );
}

Visit Rainbowkit docs to learn more about settings: https://www.rainbowkit.com/docs/installation

Link to full source code on Github