Free, MIT-licensed Next.js admin template based on Bootstrap 5.
npm run dev: dev server on http://localhost:3000npm run build: static export intoout/;npm startserves itnpm run lint: ESLint, Prettier,tscand the stats check; must passnpm test: Playwright smoke and axe tests onout/(build first;npm run test:installonce)npm run format: Prettier writenpm run stats: regeneratesrc/data/stats.jsonand the README counts
- Next.js 16 App Router, React 19, strict TypeScript,
output: "export": mock data, no server runtime.BASE_PATHsets a base path. - Routes are
src/app/(dashboard)/<name>(sidebar layout) orsrc/app/(auth)/<name>(centered layout);/is the dashboard. Every page is listed insrc/data/pages.jsonand exportsmetadata = pageMetadata("/<name>"). - Structure:
src/appholds onlypage.tsx/layout.tsx;src/layoutsthe dashboard and auth layouts;src/componentsthe shared parts (bootstrap,plugins,navbar,sidebar,ui) and, underpages/<section>/<page>/, what only one page uses;src/mocksdemo data;src/dataapp data (pages, navigation, stats). src/components/bootstrapreplaces Bootstrap's JavaScript with React components on Bootstrap's markup (Alert,Dropdown,Modal,Offcanvas);src/components/pluginswraps the plugins;src/scssis AdminKit's Sass, with the plugin overrides in5-vendor.src/lib/head-scripts.tsruns in<head>before the first paint (color mode, the hidden state of the cards that fade in); it is a self-contained function.
- Only CSS custom properties get a prefix:
--ak-*, like Bootstrap's--bs-*. Classes, Sass variables, functions, mixins and data attributes never do. - Pages are server components;
"use client"goes on the smallest component that needs state, effects or the browser. Never query or change the DOM React renders; keep it in state. - No Bootstrap JavaScript, no react-bootstrap, no Tailwind. Browser-only plugins load in
useEffectwithimport()ornext/dynamicwithssr: falseand show aSkeletonuntil they draw. - Light and dark mode:
data-bs-themeon<html>. Change the mode only throughuseColorMode(src/lib/config.ts). Colors that follow the mode use custom properties (var(--bs-body-color),var(--ak-surface-bg)); dark-only overrides go in@include color-mode(dark) { ... }at the end of the partial. Check both modes. - Charts and maps read colors from the
themeargument:<ChartJs config={(theme) => ...} />,<VectorMap options={(theme) => ...} />. - Icons are
lucide-reactcomponents with the classes of the markup (<CircleCheckBig className="align-middle" />). Images are<img>withwidth,heightandsrc={asset("/img/...")}, so the base path applies. - Counts come from
src/data/stats.json, and AdminKit PRO's fromsrc/data/editions/pro.json(a snapshot); a page description writes them as{icons.lucide}. Never type a count by hand. A new dependency goes insrc/data/plugins.json, as a plugin or innotPlugins, or lint fails. - Motion: write transitions with
@include transition(...); under reduced motion nothing moves (a fade is fine). Cards inside.reveal-cardsand.revealelements fade in on scroll without extra code (PageEffects,data-revealed). - Layout shift stays 0: reserve the final size of anything a script draws, give images
widthandheight. - Accessibility: WCAG 2.2 AA in both modes, no console errors or hydration warnings (
npm test). Text colors come fromreadable($color, $background), text on a fill fromtext-on($background). Icon-only buttons get anaria-label; card titles areh2.card-title.
- Conventional Commits, see
CONTRIBUTING.md; lefthook enforces them. - A PR that changes behaviour adds a short, user-facing line under
UnreleasedinCHANGELOG.md, like "Add pricing page (/pages-pricing)" or "Upgrade dependencies".
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in node_modules/next/dist/docs/ (resolved from this file's directory; in monorepos the next package may not be visible from the repo root) before writing any code. Heed deprecation notices.
This block is written and re-added by next dev — verify at node_modules/next/dist/server/lib/generate-agent-files.js. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.