# Nuxt

Use AdminKit in a Nuxt 4 app, add the CSS from @adminkit/core in nuxt.config and import the JavaScript in a client plugin after hydration.

Nuxt renders pages on the server and hydrates them in the browser. The AdminKit stylesheet goes in `nuxt.config.ts`, and a client plugin imports the script once the app has hydrated.

## Install

```bash
npx nuxi@latest init my-app --template minimal
cd my-app
npm install @adminkit/core
```

AdminKit PRO is not published to npm. Copy `dist/` from the download into `app/assets/adminkit/` and use `~/assets/adminkit/css/app.css` and `~/assets/adminkit/js/app.js` instead.

## Import the CSS and JavaScript

Add the stylesheet to `nuxt.config.ts`:

```ts title="nuxt.config.ts"
export default defineNuxtConfig({
  compatibilityDate: '2025-07-15',
  devtools: { enabled: true },
  css: ['@adminkit/core/css'],
})
```

Import the script in a client plugin, in the `app:mounted` hook. `app.js` changes the server-rendered markup (it renders the icons and wraps the sidebar in its scrollbar), so it has to run after Vue has hydrated that markup:

```ts title="app/plugins/adminkit.client.ts"
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('app:mounted', () => {
    import('@adminkit/core')
  })
})
```

The package ships TypeScript declarations for the import 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/
```

```ts title="nuxt.config.ts"
export default defineNuxtConfig({
  compatibilityDate: '2025-07-15',
  devtools: { enabled: true },
  css: ['@adminkit/core/css'],
  app: {
    head: {
      script: [{ src: '/head.js' }],
    },
  },
})
```

## Minimal layout

`app.js` sets up icons, the sidebar toggle and the SimpleBar scrollbar in markup that Vue renders later, also after each navigation, so the layout is plain markup with 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`).

```vue title="app/layouts/default.vue"
<script setup lang="ts">
const route = useRoute()
</script>

<template>
  <div class="wrapper">
    <nav id="sidebar" class="sidebar js-sidebar offcanvas-lg offcanvas-start" tabindex="-1" aria-label="Sidebar">
      <div class="sidebar-content js-simplebar">
        <NuxtLink class="sidebar-brand" to="/">
          <span class="align-middle">AdminKit</span>
        </NuxtLink>
        <ul class="sidebar-nav">
          <li class="sidebar-header">Pages</li>
          <li class="sidebar-item" :class="{ active: route.path === '/' }">
            <NuxtLink class="sidebar-link" to="/">
              <i class="align-middle" data-lucide="sliders-vertical"></i> <span class="align-middle">Dashboard</span>
            </NuxtLink>
          </li>
          <li class="sidebar-item" :class="{ active: route.path === '/about' }">
            <NuxtLink class="sidebar-link" to="/about">
              <i class="align-middle" data-lucide="user"></i> <span class="align-middle">About</span>
            </NuxtLink>
          </li>
        </ul>
      </div>
    </nav>

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

```vue title="app/app.vue"
<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>
```

```vue title="app/pages/index.vue"
<template>
  <h1 class="h3 mb-3">Dashboard</h1>
  <div class="card">
    <div class="card-body">Hello from AdminKit.</div>
  </div>
</template>
```

Add `app/pages/about.vue` 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, with no hydration errors in the browser console. 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/nuxt/

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
