# Angular

Add AdminKit to an Angular app through the styles and scripts arrays in angular.json and a standalone layout component with the AdminKit sidebar.

Angular CLI projects load global CSS and classic scripts through the `styles` and `scripts` arrays in `angular.json`. AdminKit's compiled files go there, and the layout is a standalone component.

## Install

```bash
npx @angular/cli@latest new my-app --defaults --style=css --ssr=false
cd my-app
npm install @adminkit/core
```

Angular CLI 22 requires Node.js `^22.22.3`, `^24.15.0` or `>=26.0.0`.

AdminKit PRO is not published to npm. Copy `dist/` from the download into `src/adminkit/` and use `src/adminkit/css/app.css` and `src/adminkit/js/app.js` in the arrays below.

## Import the CSS and JavaScript

Add the files to the build options of the project in `angular.json`. Keep `src/styles.css` after the AdminKit stylesheet so your own styles override it. Angular loads the `scripts` entry as a plain script before the app starts.

```json title="angular.json"
"options": {
  "styles": [
    "@adminkit/core/dist/css/app.css",
    "src/styles.css"
  ],
  "scripts": [
    "@adminkit/core/dist/js/app.js"
  ]
}
```

### 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>`, so copy it into the build with an `assets` entry:

```json title="angular.json"
"assets": [
  { "glob": "**/*", "input": "public" },
  { "glob": "head.js", "input": "node_modules/@adminkit/core/dist/js" }
]
```

```html title="src/index.html"
<script src="head.js"></script>
```

## Minimal layout

`app.js` sets up icons, the sidebar toggle and the SimpleBar scrollbar in markup that Angular renders later, also after each route change, 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`).

```ts title="src/app/layout/layout.ts"
import { Component } from '@angular/core';
import { RouterLink, RouterLinkActive } from '@angular/router';

@Component({
  selector: 'app-layout',
  imports: [RouterLink, RouterLinkActive],
  templateUrl: './layout.html',
})
export class Layout {}
```

```html title="src/app/layout/layout.html"
<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">
      <a class="sidebar-brand" routerLink="/">
        <span class="align-middle">AdminKit</span>
      </a>
      <ul class="sidebar-nav">
        <li class="sidebar-header">Pages</li>
        <li class="sidebar-item" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">
          <a class="sidebar-link" routerLink="/">
            <i class="align-middle" data-lucide="sliders-vertical"></i> <span class="align-middle">Dashboard</span>
          </a>
        </li>
        <li class="sidebar-item" routerLinkActive="active">
          <a class="sidebar-link" routerLink="/profile">
            <i class="align-middle" data-lucide="user"></i> <span class="align-middle">Profile</span>
          </a>
        </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">
        <ng-content />
      </div>
    </main>
  </div>
</div>
```

Replace the generated root component and its template, and delete `src/app/app.css`. The dashboard is a route:

```ts title="src/app/app.ts"
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { Layout } from './layout/layout';

@Component({
  imports: [RouterOutlet, Layout],
  selector: 'app-root',
  templateUrl: './app.html',
})
export class App {}
```

```html title="src/app/app.html"
<app-layout>
  <router-outlet />
</app-layout>
```

```ts title="src/app/dashboard.ts"
import { Component } from '@angular/core';

@Component({
  template: `
    <h1 class="h3 mb-3">Dashboard</h1>
    <div class="card">
      <div class="card-body">Hello from AdminKit.</div>
    </div>
  `,
})
export class Dashboard {}
```

```ts title="src/app/app.routes.ts"
import { Routes } from '@angular/router';
import { Dashboard } from './dashboard';

export const routes: Routes = [{ path: '', component: Dashboard }];
```

Add a `profile` route and component the same way for the second link.

## Run

```bash
npx ng serve
```

Open http://localhost:4200. You should see the dark sidebar with its two icons, the navbar with the hamburger toggle and the card. Clicking **Profile** 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.

## Notes

- `ng build` stops at Angular's default `initial` budget of 1 MB, because `app.css` and `app.js` add about 830 kB. Raise `maximumError` of the `initial` budget in `angular.json`, for example to `2MB`.
- With server-side rendering (`--ssr`), the server renders the pages without `app.js`, and the browser runs it from `scripts` before the app hydrates. Hydration works as is.

---

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

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
