Aurelia 2 Admin
June 19, 2026 · View on GitHub
An Aurelia 2 admin panel starter with a calm, minimal UI, Tailwind v4 styling, and a fully featured route map you can grow into a real product. Built so a new page is a one-line change and the pieces drop cleanly into an existing Aurelia 2 app.
Highlights
- Aurelia 2 RC1 + Router, webpack, Tailwind v4
- Single source of truth for navigation — routes and the sidebar are generated
from one config (
src/navigation.ts). No more keeping a route table and a menu in sync. - Lazy-loaded routes — every page is code-split and fetched on first visit
- Active-link highlighting in the sidebar, driven by the router
- Reusable UI components —
<app-icon>,<page-header>,<stat-card>(registered globally, usable anywhere with no<import>) - Centralised theming —
ThemeServiceowns dark mode; toggle lives in the topbar and the settings page, always in sync - Responsive shell — collapsible sidebar drawer on mobile
- Auth scaffold with localStorage session, login page, and a route guard
- A 404 / not-found route with a catch-all fallback
- 24 ready-made admin pages across Core, Team, Operations, and Workspace groups
Getting started
Requirements: latest Node and npm.
npm install
npm start # dev server on http://localhost:9000
npm run build # production build to dist/
npm run lint # eslint + htmlhint
npm test # jest (scaffolded; passes with no tests)
Default login
- Email:
admin@example.com - Password:
password
Replace the hardcoded credentials in src/services/auth-service.ts with your auth provider.
Adding a page (one step)
Add an entry to the relevant group in src/navigation.ts:
{ path: 'invoices', title: 'Invoices', icon: 'billing', load: () => import('./routes/invoices') },
Then create src/routes/invoices.ts + src/routes/invoices.html. That single entry wires up:
- the route (lazy-loaded, with the page title), and
- the sidebar link (with icon and active-state highlighting).
Start the template with the shared header component:
<div class="page">
<page-header heading="Invoices" subheading="Track and reconcile billing.">
<button class="btn-primary">New invoice</button>
</page-header>
<!-- page content -->
</div>
Project structure
src/navigation.ts— the navigation tree; the single source of truth for routes + sidebarsrc/app.ts— the root component: builds the route table, owns shell state (mobile drawer, theme)src/app.html— the shell layout (sidebar, topbar, viewport)src/app.css— theme tokens, component styles, layout utilitiessrc/components/— shared, globally-registered UI componentsapp-icon— named inline-SVG icon registry (<app-icon name="users">)page-header— standard page title + actions slotstat-card— compact metric card
src/services/—auth-service,theme-servicesrc/routes/— one view-model + template per page
Components
All three are registered globally in src/main.ts, so use them in any template directly.
<app-icon name="dashboard"></app-icon>
<page-header heading="Users" subheading="Manage access and roles.">
<button class="btn-primary">Add user</button>
</page-header>
<stat-card label="Active Users" value="1,234" delta="+12%" hint="Last 7 days"></stat-card>
To add an icon, drop a <svg case="my-icon" class="icon" ...> entry into
src/components/app-icon.html and reference it by name.
Routing notes
- Routes are derived from
navigation.tsviabuildRoutes()and wrapped in aNavigationStrategyso each page's chunk loads only when visited. ''redirects todashboard; unmatched paths fall through to anot-foundpage.- Route guarding lives in
src/auth-hook.ts(a global@lifecycleHookscanLoad).
Theming
- Global tokens (
--surface,--stroke,--accent, type scales…) live at the top ofsrc/app.css. ThemeService(src/services/theme-service.ts) is the only place that toggles/persists dark mode. It applies thedarkclass to<html>, persists tolocalStorage, and falls back to the OS preference. The topbar toggle and the settings page both go through it.
Data integration
Every page uses placeholder arrays inside its view-model (e.g. src/routes/users.ts). To wire
up a backend:
- Create a service in
src/services/. - Inject it with
resolve()and load data in a route hook (canLoad/loading) orbinding(). - Map your API models into the templates.
Navigation and permissions
To gate pages by role or plan, filter navigation in src/app.ts's routerNavs getter, and/or
add checks in src/auth-hook.ts for hard route enforcement.
Use as a drop-in for an existing Aurelia 2 app
- Copy
src/components/and register them in yourmain.ts(Aurelia.register(...components)). - Copy
src/services/theme-service.tsfor dark mode. - Copy
src/navigation.tsand adapt the groups; mergebuildRoutes()into your@routeconfig. - Lift
src/app.html/src/app.cssshell markup and tokens as needed.
Tailwind v4 setup
src/app.cssuses@import "tailwindcss";and@config "../tailwind.config.js";webpack.config.jsuses@tailwindcss/postcss
Environment
Optional .env / .env.development files are supported via dotenv-webpack.