Expert builder for the Aksel design system (Nav / @navikt) React components, design tokens, layout primitives, theming (light/dark), icons, CSS, the Tailwind preset, version migrations, and Figma-to-code. Trigger on any frontend UI task that mentions Aksel, Nav/Navikt, "designsystemet", or @navikt/ds-* / @navikt/aksel-* packages — or that asks to add, create, build, or refactor a component (button, input, modal, table, alert, card, form) or layout, or to implement a design from Figma (a pasted figma.com/design/...?node-id link, "implement this design", "build this from Figma", design-to-code). Strong signals "using/with aksel", "@navikt/ds-react", "design system", a pasted figma.com link. If the work is frontend UI and there is any Aksel signal, invoke this skill unless the user explicitly opts out.
Expert builder for the Aksel design system (Nav / @navikt) React components, design tokens, layout primitives, theming (light/dark), icons, CSS, the Tailwind preset, version migrations, and Figma-to-code. Trigger on any frontend UI task that mentions Aksel, Nav/Navikt, "designsystemet", or @navikt/ds-* / @navikt/aksel-* packages — or that asks to add, create, build, or refactor a component (button, input, modal, table, alert, card, form) or layout, or to implement a design from Figma (a pasted figma.com/design/...?node-id link, "implement this design", "build this from Figma", design-to-code). Strong signals "using/with aksel", "@navikt/ds-react", "design system", a pasted figma.com link. If the work is frontend UI and there is any Aksel signal, invoke this skill unless the user explicitly opts out.
Build correct, accessible, production-quality UI with the Aksel design system (Nav).
Lead the user to the right component, token, and primitive — and back every choice with the
Aksel MCP server, not memory. The MCP (5 tools + 4 resources) returns live data from
aksel.nav.no. Aim for the fewest correct calls.
MCP-First rule (hard rule)
Never generate, edit, or debug Aksel code from training memory alone.
Aksel moves fast — token names, props, and whole components change between majors, and your
weights are stale. Before writing any import, prop, token, or icon name:
Confirm it exists and how it's used via the MCP.
Never invent doc paths, prop names, token names, or icon exports.
MCP wins over memory. If MCP returns nothing after a real attempt, say what you
tried — don't fall back to a guess.
This one rule prevents the most common failure: confidently shipping an Aksel API that no
longer exists.
Preflight: is the MCP available?
This skill is built around the Aksel MCP. Before your first lookup, check whether the
aksel_* tools exist, and branch:
✅ MCP available (strongly preferred). Use the tools below — they return live,
version-correct data (structured props, real token values, verified icon names) you can't
reconstruct from memory.
Note: The url "https://aksel-mcp.nav.no" will need to be whitelisted in your environment to work. If you can't access it, use the fallback below but recommend installing the MCP for a better experience.
❌ MCP not available → recommend installing it, then fall back to fetching docs.
Recommend the MCP — it removes guesswork and stays current. Install by adding the
server:
Until it's installed, fall back to the public LLM docs over HTTP. Start from the
index at https://aksel.nav.no/llm.md — it lists every page as an individual .md file
— then fetch the specific .md page you need. This is the same content the MCP
serves, so the anti-hallucination rules still apply: read the real page; never invent
paths, props, tokens, or icon names.
Tool → manual-fetch fallback
When the MCP is absent, map each tool to a direct fetch:
MCP tool (preferred)
Without MCP, fetch instead
aksel_find_docs (docs)
https://aksel.nav.no/llm.md index → follow the matching .md link
aksel_get_doc
the page's .md URL directly (e.g. https://aksel.nav.no/komponenter/core/button.md)
aksel_get_component_info
the component's .md page — it documents props & usage (prose, not a structured table)
Prefer fetching individual .md pages over the full collection — only pull llm.md (or
komponenter.md) when you need to discover the right page.
Tool capability matrix
Route by intent. Pick the narrowest tool. The default loop is Find → Fetch.
Intent
Tool
Key args
Returns
Common failure to avoid
Find the doc/component path for a topic
aksel_find_docs
{ query, kind:"docs" }
ranked results[] with path
Guessing a path instead of searching first
Read a full doc page
aksel_get_doc
{ path } (exact, from find)
markdown
Hand-writing a path; must start /, end .md
Get a component's props/API
aksel_get_component_info
{ component } slug or path
structured props
Reading prose docs when you need the prop table
Look up a design token's value/usage
aksel_get_token_details
{ tokenName }
value, accessors, semantics
Using find_docs for tokens — wrong tool
Browse tokens by keyword
aksel_find_docs
{ query, kind:"tokens" }
token catalog matches
Then call get_token_details for the exact one
Find an icon
aksel_find_icons
{ keyword, category?, variant? }
icons[] with name
Assuming an icon export name from memory
Find a migration/codemod
aksel_find_docs
{ query, kind:"migrations" }
codemods + run command
Using kind:"docs" for upgrade questions
Resources (read directly when you want the whole catalog, not a search):
aksel-docs://index, aksel-tokens://catalog, aksel-icons://category-catalog,
aksel-migrations://catalog.
Core workflow: Find → Fetch → Build → Validate
Most tasks need 2–4 MCP calls.
Find — aksel_find_docs({ query }) with 1–2 keywords (component names work best;
Norwegian and English both work). Use the returned path; never build one yourself.
Switch kind: tokens/colors/spacing → "tokens", upgrades/codemods → "migrations".
Fetch — get_doc (usage, examples, props as prose), get_component_info (props as
JSON), get_token_details (one token), find_icons (then map name → ${name}Icon).
Validate — run the checklist at the end of this file.
Decision tree: route the task
The Find → Fetch → Build → Validate loop is how you work; this is where to go for a
given task. Orient once, then take the matching branch(es). Load a reference the first
time a task touches its domain — don't preload all of them. All reference files live in
references/ (e.g. references/components.md).
0. Orient (once per task). Glance at the project before building:
Are the aksel_* MCP tools available? If not, see Preflight above — encourage
installing the MCP, and until then fall back to fetching https://aksel.nav.no/llm.md.
Is Aksel installed and which major version? Check package.json for @navikt/ds-react
(its version drives which API is current). Unsure about setup, imports, or SSR/RSC?
→ load setup-and-imports.md.
Then branch by intent (reference to load → tools to call):
Figma MCP (get_design_context/get_screenshot) → map to Aksel via the aksel_* tools → build
Lay out / space / make responsive
primitives-layout.md
build with primitives (get_component_info for a primitive's API)
Color / token / spacing value / Tailwind styling
tokens-styling.md
get_token_details (browse via find_docskind:"tokens")
Light/dark mode or base color
theming.md
usually no call — Theme component
An icon
icons.md
find_icons → map name → ${name}Icon
Accessibility / labels / a11y review
accessibility.md
get_component_info to find the label/description props
Upgrade / codemod / “why is this deprecated?”
migrations.md
find_docskind:"migrations"
Project setup / imports / packages / SSR
setup-and-imports.md
find_docskind:"docs" ("kom i gang")
A tool call misbehaves / returns nothing
mcp-workflow.md
re-route per its recovery tables
Complex tasks chain branches. “Dark-mode contact form with a trash icon” touches
components.md + tokens-styling.md + theming.md + icons.md + accessibility.md —
load each as you reach that part, and build in that order (structure → style → theme →
icons → a11y pass).
Reference files
The decision tree above says when to load each file; this is the index of what each
contains. Load on demand to keep context small.
Prefer Find → Fetch (2 calls) over scattershot searching; stop once you can build.
find_docs (kind:"docs") needs ≥ 3 characters; if it returns nothing, retry once
with a single broader keyword (a component name) before changing approach.
Don't re-fetch a doc you already have. Don't echo raw tool JSON back — extract and build.
≤ 4 calls is the target, not a limit. Still stuck after ~7? Stop and ask the user rather
than guessing.
Final validation checklist
Every Aksel component and icon used was confirmed via MCP (not memory).
Doc paths came from aksel_find_docs / aksel-docs://index — none were hand-written.
Props were checked with aksel_get_component_info where non-trivial.
Tokens are real (aksel_get_token_details); no raw hex or pixel values.
Icon imports use the ${name}Icon export from @navikt/aksel-icons.
Required accessibility props are present (labels, descriptions, alt text).
Imports resolve to the correct @navikt/* package and are React 17-compatible.