1. Docs
  2. Installation
  3. Next.js

Next.js

Install and configure Next.js.

Create project

Start by creating a new Next.js project using create-next-app:

Terminal
npx create-next-app@latest --tailwind --ts --empty --app --src-dir --turbopack

You will be asked a few questions to create the project:

? What is your project named? » my-app
? Which linter would you like to use? » Biome
? Would you like to customize the default import alias (@/*)? » No / Yes

Currently, I prefer to use Biome.js instead of ESLint. You can use ESLint if you prefer. Also I prefer to use ~ as the alias. You can use @ or any other alias if you prefer.

Run the shadcn CLI

Run the shadcn init command to setup your project:

npx shadcn@latest init

Remove unused shadcn packages

Kanpeki uses modern tooling instead of shadcn's defaults. Remove packages you won't need:

npm remove class-variance-authority clsx tw-animate-css

Why? Kanpeki uses CVA beta and tailwindcss-motion instead. See the introduction for details.

Delete these files:

  • src/lib/utils.ts (optional - keep if you have other utilities)

Remove this import from src/styles/globals.css:

globals.css
@import "tailwindcss";
@import "tw-animate-css";

That's it ✨

You can now start adding components to your project.

npx shadcn@latest add @kanpeki/button

The command above will add the Button component to your project. You can then import it like this:

import { Button } from "~/components/ui/button"; 

export default function Home() {
  return (
    <div>
      <Button>Click me</Button>
    </div>
  );
}

Fonts (optional)

I use Geist as the default font. You can use any font you like.

Here's how I configure Geist for Next.js:

1. Create a fonts.ts file inside src/config:

import { Geist } from "next/font/google";

const sans = Geist({
  subsets: ["latin"],
  variable: "--font-sans",
});

export const fonts = [sans.variable];

2. Import the font in the root layout:

import "~/styles/globals.css";

import type { Metadata, Viewport } from "next";
import { fonts } from "~/config/fonts"; 
import { cx } from "cva";

export const metadata: Metadata = {
  title: {
    default: "Next.js app",
    template: "%s | Next.js app",
  },
};

export const viewport: Viewport = {
  themeColor: [
    { media: "(prefers-color-scheme: light)", color: "white" },
    { media: "(prefers-color-scheme: dark)", color: "black" },
  ],
};

interface LayoutProps {
  children: React.ReactNode;
}

export default function Layout({ children }: LayoutProps) {
  return (
    <html className={cx(fonts)} lang="en" suppressHydrationWarning>
      <body>
        {children}
      </body>
    </html>
  );
}

3. Configure --font-sans in globals.css

globals.css
@import "tailwindcss";

@plugin "tailwindcss-react-aria-components";
@plugin "tailwindcss-motion";

@custom-variant dark (&:where(.dark, .dark *));

@theme inline {
  --font-sans: var(--font-sans), ui-sans-serif, system-ui, sans-serif,
    "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";

  ...
}

App structure

Here's how I structure my Next.js apps. You can use this as a reference:

components.json
next.config.ts
package.json
postcss.config.js
tsconfig.json
  • I place the UI components in the src/components/ui folder.
  • The lib folder contains configuration for external libraries.
  • The styles folder contains the global CSS.