The shared visual design system from ITK Aarhus for the digital products it builds for Aarhus Kommune — one palette, one type stack, one set of primitives, used from public sites down to internal tools. Aarhus Kommune is the institutional brand, expressed quietly as a footer endorsement; each product carries its own name in the header.
Live preview: https://itk-dev.github.io/itkaarhus-design-system/
The reference site is built with Astro so it can be served locally with a single command. The design system itself is plain CSS — token and component files you can drop into any project, no framework required.
The repo is an assets-only Composer package (itk-dev/itkaarhus-design-system).
Add it as a VCS repository and require it:
The payload installs to vendor/itk-dev/itkaarhus-design-system/assets/:
tokens.css— every--itkaarhus-*custom property (colors, type, spacing, radii, shadows, focus). Load first.components.css— the namespaced.itkaarhus-*component classes (buttons, links, tags, inputs, cards, callouts, stats, KPI cards, tables, timeline, breadcrumb, heatmap, meters). Requirestokens.css.lucide-sprite.svg— the Lucide icon sprite.logos/aak-emblem.svg/logos/aak-emblem-hvid.svg— the Aarhus Kommune emblem (crest only, no wordmark; intrinsic 32px tall) in dark and white, for the product header / sidebar mark.
Copy or serve those files from your app's public path (there is no PHP
autoload — nothing else in the package is needed at runtime). The same files are
also published on GitHub Pages at
https://itk-dev.github.io/itkaarhus-design-system/{tokens.css,components.css,assets/lucide-sprite.svg,assets/logos/aak-emblem.svg}.
assets/tokens.css— the single source of truth for tokens: CSS custom properties (colors, type scale, spacing, radii, shadows, focus).assets/components.css— all shared.itkaarhus-*component rules, extracted from the reference pages.assets/lucide-sprite.svg— the Lucide icon set used by the system.assets/logos/— the emblem-only Aarhus Kommune marks (aak-emblem.svgdark,aak-emblem-hvid.svgwhite), derived from the suppliedAAK_02_*lockups.npm run sync:assetscopies the payload files above intopublic/(run automatically ondev/build) so the site serves them at stable URLs; the copies are git-ignored — edit onlyassets/.src/layouts/Layout.astro— shared page shell: the persistent left sidebar and the<head>(fonts, favicon); importsassets/tokens.css.src/styles/sidebar.css— sidebar styling (replaces the old top-bards-nav.css).src/pages/index.astro— overview page with previews of every section.src/pages/colors.astro— palette, color scales, and usage rules.src/pages/typography.astro— Inter + Newsreader (system monospace).src/pages/spacing.astro— 4px-base spacing, radii, elevation.src/pages/logo.astro— Aarhus Kommune endorsement mark, product header lockup, clear space, misuse.src/pages/components.astro— buttons, tags & status, inputs, cards, callouts, stats, editorial type, KPI cards, graphs & diagrams, expandable table, timeline, nav, breadcrumb; the component rules themselves live inassets/components.css.src/scripts/chart-theme.ts— shared Chart.js theme: reads the--itkaarhus-*tokens at runtime and exposes the categorical palette + defaults (flat fills, no gradients).src/pages/examples/*.astro— thin wrappers that iframe each applied example, keeping the sidebar in place.public/examples/— the standalone example documents (a fictional "Mit Aarhus" municipal product):website-landing.html,website-content.html,website-about.html,app-dashboard.html,app-data-tables.html,app-statistics.html, plus sharedsite.css(public site chrome) andapp.css(logged-in app shell).public/assets/logos/— the Aarhus Kommune marks (AAK_02_*.svg) + favicon (aak-favicon.ico).
Two brand colours, four state colours, and a neutral gray scale. Every colour
ships a 50→900 scale (-50 lightest → -900 darkest); 500 is the base hue.
| Scale | Base hex | Role |
|---|---|---|
--itkaarhus-blue-* |
#007BA6 |
Primary — links, primary buttons, focus, active state |
--itkaarhus-coral-* |
#FF5F31 |
Secondary — warm complement; highlights, editorial accents (not an error colour) |
--itkaarhus-info-* |
#00A5CD |
State — informational |
--itkaarhus-success-* |
#008D3D |
State — success / "active" |
--itkaarhus-warning-* |
#F5B800 |
State — warning |
--itkaarhus-danger-* |
#CC1F33 |
State — danger, errors (a true cool red, kept distinct from coral; sharp and rare) |
--itkaarhus-gray-* |
— | Neutral — text, surfaces, borders (50→900; numbered only) |
--itkaarhus-white is true white for page backgrounds. Role aliases:
--itkaarhus-primary (+ -hover), --itkaarhus-secondary, and
--itkaarhus-{info,success,warning,danger} — each state with a *-soft surface
tint for badges/alerts.
- Display, UI & body:
Inter400/500/600/700 — app chrome, dense dashboards, long-form prose, and small text. - Serif (editorial):
Newsreader— opt-in for website-style surfaces (heroes, overviews, KPI numbers) via--itkaarhus-font-serif. Not for app chrome. - Mono: system default (
ui-monospace, …) — the DS ships no web monospace font. - Scale (px): 12, 14, 16, 18, 22, 28, 36, 48, 64, 88
- Eyebrows: plain uppercase labels in app chrome; the leading rule ("the dash") is reserved for the editorial / serif voice.
- Tone: Danish-first, calm, gov-grade. Negative letter-spacing on display sizes.
- Lucide line icons (24px viewBox,
currentColor, stroke 2). The icon set ships asassets/lucide-sprite.svg(served atassets/lucide-sprite.svgon the site) — reference a symbol with<svg class="icon"><use href="assets/lucide-sprite.svg#lucide-NAME"></use></svg>(resolve the path against the site base). Don't hand-roll SVG paths. (Consuming apps may wrap this in their own helper — e.g. a{{ ui.icon('name') }}Twig macro — but the sprite is the source.)
- Charts use Chart.js (bar, line/area, donut,
sparkline), themed from the tokens at runtime via
src/scripts/chart-theme.ts(it reads--itkaarhus-*off:root). Flat fills only — no gradients — drawn from the categorical palette: blue, coral, info, success, warning, gray. - Heatmaps and progress/meter bars are hand-rolled CSS (no library) —
intensity uses the blue scale (
blue-100→blue-500). - Astro pages bundle Chart.js via
import 'chart.js/auto'. The standalonepublic/examples/pages load a vendored copy atexamples/vendor/chart.umd.min.js, copied from the npm dependency bynpm run sync:vendor(run automatically ondev/build; thevendor/dir is git-ignored). - Canvas charts carry an
aria-labelsummary, since canvas content isn't readable by assistive tech.
- Clarity over cleverness — calm, gov-grade, long-form Danish.
- Blue leads, coral accents sparingly, state colours carry meaning, red stays sharp and rare.
- No emoji, no illustrative SVG, no gradient backgrounds — flat brand fills only.
- The palette is the expression — let the colours do the lifting.
Install dependencies once, then start the dev server:
npm install
npm run dev
# then visit the printed URL (http://localhost:4321/itkaarhus-design-system/)To build the static site and preview the production output:
npm run build # outputs to dist/
npm run previewThe site is served under the /itkaarhus-design-system/ base path (matching
GitHub Pages), configured in astro.config.mjs.
main is continuous — merge PRs into it freely; merging does not deploy. A
release is shipped by pushing a bare-semver tag (e.g. 0.2.0), which triggers
.github/workflows/pages.yml to build the Astro site on Node 22 and deploy dist/
to GitHub Pages → https://itk-dev.github.io/itkaarhus-design-system/.
To cut a release once main holds the changes you want to ship:
git checkout main && git pull --ff-only
# roll CHANGELOG [Unreleased] → [<tag>] - <date>, bump VERSION + package.json, commit (via a PR)
git tag 0.2.0 # bare semver, no "v" prefix — match the existing tags
git push origin 0.2.0 # this is the release; it triggers the deployRepo setting (one-time): the deploy runs in the
github-pagesenvironment, which restricts which refs may deploy. Because we deploy from tags, that environment must allow tag refs — under Settings → Environments → github-pages → Deployment branches and tags, add a tag rule matching*.*.*(alongside themainbranch). Without it, a tagged deploy is rejected with "Tag … is not allowed to deploy to github-pages due to environment protection rules" before the build even starts. This lives in repo settings, not inpages.yml.
Tag naming and the changelog/version bump follow the ITK Dev release flow — see the
/itkdev-release skill. A manual workflow_dispatch run is available as a fallback.
The same bare-semver tags double as the Composer package versions — consumers
requiring itk-dev/itkaarhus-design-system via a VCS repository resolve ^0.4
etc. from these tags, so a tag push releases both the site and the package.