# Next.js

Use AdminKit with the Next.js App Router, import the CSS from @adminkit/core in the root layout and the JavaScript in a client component after hydration.

In the App Router, the root layout imports the AdminKit stylesheet, and a client component imports the script once React has hydrated the page.

## Install

```bash
npx create-next-app@latest my-app --ts --app --no-tailwind --no-src-dir
cd my-app
npm install @adminkit/core
```

AdminKit PRO is not published to npm. Copy `dist/` from the download into `adminkit/` in the project and import `@/adminkit/css/app.css` and `@/adminkit/js/app.js` instead.

## Import the CSS and JavaScript

Import the stylesheet in `app/layout.tsx`. Delete `app/globals.css` and `app/page.module.css` from the starter, because their styles conflict with AdminKit. The script is imported by the layout component below.

```tsx title="app/layout.tsx"
import type { Metadata } from "next";
import "@adminkit/core/css";
import Layout from "@/components/layout";

export const metadata: Metadata = {
  title: "Dashboard",
};

export default function RootLayout({ children }: LayoutProps<"/">) {
  return (
    <html lang="en">
      <body>
        <Layout>{children}</Layout>
      </body>
    </html>
  );
}
```

The package ships TypeScript declarations for both imports and for the globals `app.js` adds, such as `window.adminkit`.

### Optional: avoid a color mode flash

Without `head.js`, `app.js` applies the stored [color mode](/docs/getting-started/dark-mode/) once it runs, so a visitor who picked the mode opposite to their operating system briefly sees the other one. `head.js` applies it before the first paint. It has to be a plain, blocking script in `<head>`, served from `public/`:

```bash
cp node_modules/@adminkit/core/dist/js/head.js public/
```

It sets `data-bs-theme` on `<html>` before React hydrates, so `<html>` also needs `suppressHydrationWarning`:

```tsx
<html lang="en" suppressHydrationWarning>
  <head>
    <script src="/head.js"></script>
  </head>
```

## Minimal layout

The layout is a client component (`"use client"`). Its effect imports `app.js` once React has hydrated the page: `app.js` changes the server-rendered markup (it renders the icons and wraps the sidebar in its scrollbar), and React reports a hydration error if that happens first. From then on `app.js` sets up the icons, the sidebar toggle and the SimpleBar scrollbar in every page Next.js renders, through the `js-sidebar`, `js-simplebar` and `js-sidebar-toggle` classes. From the `lg` breakpoint the toggle collapses the sidebar; below it, the sidebar is a Bootstrap offcanvas sheet (`offcanvas-lg` on `#sidebar`).

```tsx title="components/layout.tsx"
"use client";

import Link from "next/link";
import { usePathname } from "next/navigation";
import { useEffect, type ReactNode } from "react";

export default function Layout({ children }: { children: ReactNode }) {
  const pathname = usePathname();

  useEffect(() => {
    import("@adminkit/core");
  }, []);

  return (
    <div className="wrapper">
      <nav id="sidebar" className="sidebar js-sidebar offcanvas-lg offcanvas-start" tabIndex={-1} aria-label="Sidebar">
        <div className="sidebar-content js-simplebar">
          <Link className="sidebar-brand" href="/">
            <span className="align-middle">AdminKit</span>
          </Link>
          <ul className="sidebar-nav">
            <li className="sidebar-header">Pages</li>
            <li className={`sidebar-item${pathname === "/" ? " active" : ""}`}>
              <Link className="sidebar-link" href="/">
                <i className="align-middle" data-lucide="sliders-vertical"></i> <span className="align-middle">Dashboard</span>
              </Link>
            </li>
            <li className={`sidebar-item${pathname === "/about" ? " active" : ""}`}>
              <Link className="sidebar-link" href="/about">
                <i className="align-middle" data-lucide="user"></i> <span className="align-middle">About</span>
              </Link>
            </li>
          </ul>
        </div>
      </nav>

      <div className="main">
        <nav className="navbar navbar-expand navbar-light navbar-bg" aria-label="Top bar">
          <button type="button" className="sidebar-toggle js-sidebar-toggle" aria-controls="sidebar" aria-expanded="true" aria-label="Collapse sidebar">
            <i className="hamburger align-self-center"></i>
          </button>
        </nav>
        <main className="content">
          <div className="container-fluid p-0">{children}</div>
        </main>
      </div>
    </div>
  );
}
```

```tsx title="app/page.tsx"
export default function Home() {
  return (
    <>
      <h1 className="h3 mb-3">Dashboard</h1>
      <div className="card">
        <div className="card-body">Hello from AdminKit.</div>
      </div>
    </>
  );
}
```

Add `app/about/page.tsx` the same way for the second link.

## Run

```bash
npm run dev
```

Open http://localhost:3000. You should see the dark sidebar with its two icons, the navbar with the hamburger toggle and the card. Clicking **About** navigates client-side; the icons stay rendered and the active item moves. In a window narrower than 992px the sidebar is hidden, and the toggle opens it as a sheet over the page; Escape, the backdrop or a link closes it.

---

Canonical HTML page: https://adminkit.io/docs/frameworks/nextjs/

Site overview for agents: https://adminkit.io/llms.txt (expanded: https://adminkit.io/llms-full.txt) · Documentation: https://adminkit.io/docs/ · Questions: support@adminkit.io
