Komponenter
Kom i gang på 5 minutter
Teknisk oppsett
Ny funksjon
Denne komponenten er ny eller oppdatert. Tar du den i bruk ønsker vi gjerne innspill til hvordan den fungerer i tjenesten din!
Egnet til:
- Eksterne flater
Denne guiden viser deg to veier til en fungerende Dekoratør-integrasjon i din app:
| Alternativ | Tilnærming | Passer for |
|---|---|---|
| Alternativ 1 | Bruk nav-pilot-skillen | Første gang, eller når du vil ha veiledning gjennom hele oppsettet |
| Alternativ 2 | Manuelt oppsett | Kjent med Dekoratøren, vil bare ha koden |
For en mer teknisk gjennomgang kan du lese applikasjonens Readme.
Forutsetninger
- Node.js og npm/pnpm
- GitHub PAT med
read:packages-scope og navikt SSO-autorisasjon - En Nais-app
Velg integrasjonsmetode
Før du setter opp Dekoratøren, må du velge hvordan den skal hentes og rendres. SSR via moduler-pakken er anbefalt i de aller fleste tilfeller.
Har du en server (Next.js, Express, Ktor, …)?├─ Ja → Bruk SSR via moduler-pakken ✅ Anbefalt│ – ingen layout shift│ – moduler-pakken håndterer miljø, service discovery og fallback automatisk│├─ Ja, men kan ikke bruke moduler-pakken│ (f.eks. ikke-JS-backend) → Tilpasset SSR-implementasjon ⚠️ Se nedenfor│└─ Nei (ren SPA uten server) → CSR ⚠️ Siste utveiSSR via moduler-pakken (anbefalt)
Appen kaller fetchDecoratorReact eller fetchDecoratorHtml på serveren og injiserer HTML/React-komponenter i layouten. Moduler-pakken håndterer miljø, service discovery og fallback automatisk.
→ Dette er det steg 4 i manuelt oppsett viser.
Tilpasset SSR-implementasjon
Hvis du ikke bruker en JavaScript-server (f.eks. Kotlin/Ktor, Java/Spring Boot, Go), kaller du Dekoratørens /ssr-endepunkt direkte og setter inn de fire fragmentene i din HTML-respons:
GET https://www.nav.no/dekoratoren/ssr?context=privatperson&language=nbResponsen er JSON med fire felter:
{ "headAssets": "<!-- CSS, favicons → inn i <head> -->", "header": "<!-- Header-innhold → inn rett før appinnholdet -->", "footer": "<!-- Footer-innhold → inn rett etter appinnholdet -->", "scripts": "<!-- <script>-elementer → kan plasseres hvor som helst -->"}Legg til access policy som normalt (steg 3 i manuelt oppsett).
CSR (ikke anbefalt)
CSR gir layout shift og dårligere FCP. Bruk kun hvis SSR ikke er teknisk mulig.
import { injectDecoratorClientSide } from "@navikt/nav-dekoratoren-moduler";
injectDecoratorClientSide({ env: "prod", params: { context: "privatperson" },});Alternativ 1: Bruk nav-pilot-skillen
Den raskeste veien til et korrekt oppsett er å bruke nav-dekoratøren-skillen i GitHub Copilot Chat. Skillen dekker installasjon, SSR/CSR-integrasjon, konfigurasjon, analytics, samtykke/cookies og bidrag til selve dekoratøren.
Slik bruker du den
1. Åpne GitHub Copilot Chat i VS Code, Cursor eller på GitHub.com
2. Velg nav-pilot som agent.
3. Skriv en melding som beskriver situasjonen din, for eksempel:
“Use the /nav-dekoratoren skill to help me integrate the decorator in my Next.js app”
4. Copilot vil stille oppklarende spørsmål ved behov og generere klar-til-bruk kode for:
app/layout.tsx(ellerpages/_document.tsx).npmrc- Access policy i
nais.yaml - CSP-header
- Breadcrumbs og språkvelger (om ønsket)
Jo mer kontekst du gir (rammeverk, miljø, hvilke funksjoner du trenger), desto mer presis blir koden du får ut.
Alternativ 2: Manuelt oppsett
Steg 1 – Installer pakken
npm install --save @navikt/nav-dekoratoren-modulerLegg til i .npmrc:
@navikt:registry=https://npm.pkg.github.comLogg inn med PAT:
npm login --registry=https://npm.pkg.github.com --auth-type=legacySteg 2 – GitHub Actions
- uses: actions/setup-node@v4 with: registry-url: "https://npm.pkg.github.com"
- run: npm ci env: NODE_AUTH_TOKEN: ${{ secrets.READER_TOKEN }}Steg 3 – Access policy i nais.yaml
accessPolicy: outbound: rules: - application: nav-dekoratoren namespace: personbrukerSteg 4 – Hent og vis Dekoratøren
Next.js App Router (app/layout.tsx):
import { fetchDecoratorReact } from "@navikt/nav-dekoratoren-moduler/ssr";import Script from "next/script";
export default async function RootLayout({ children }: { children: React.ReactNode }) { const Decorator = await fetchDecoratorReact({ env: "prod", params: { context: "privatperson", language: "nb" }, });
return ( <html lang="nb"> <head> <Decorator.HeadAssets /> </head> <body> <Decorator.Header /> {children} <Decorator.Footer /> <Decorator.Scripts loader={Script} /> </body> </html> );}Next.js Page Router (pages/_document.tsx):
import { fetchDecoratorReact, type DecoratorComponentsReact } from "@navikt/nav-dekoratoren-moduler/ssr";import Document, { Head, Html, Main, NextScript, type DocumentContext, type DocumentInitialProps } from "next/document";
type MyDocumentProps = DocumentInitialProps & { Decorator: DecoratorComponentsReact };
class MyDocument extends Document<MyDocumentProps> { static async getInitialProps(ctx: DocumentContext): Promise<MyDocumentProps> { const initialProps = await Document.getInitialProps(ctx); const Decorator = await fetchDecoratorReact({ env: "prod", params: { context: "privatperson", language: "nb" }, }); return { ...initialProps, Decorator }; }
render() { const { Decorator } = this.props; return ( <Html lang="nb"> <Head> <Decorator.HeadAssets /> </Head> <body> <Decorator.Header /> <Main /> <Decorator.Footer /> <Decorator.Scripts /> <NextScript /> </body> </Html> ); }}
export default MyDocument;Express/Node (HTML-fragmenter):
import { fetchDecoratorHtml } from "@navikt/nav-dekoratoren-moduler/ssr";
const { DECORATOR_HEAD_ASSETS, DECORATOR_HEADER, DECORATOR_FOOTER, DECORATOR_SCRIPTS } = await fetchDecoratorHtml({ env: "prod", params: { context: "privatperson" }, });Steg 5 – Verifiser lokalt
Start appen og sjekk at headeren og footeren fra nav.no vises. Hvis du ser layout shift, er du sannsynligvis på CSR — bytt til fetchDecoratorReact (SSR).
Alternative valg
Breadcrumbs og språkvelger
Bruk handleInApp: true når appen selv skal håndtere routing (f.eks. med Next.js router.push eller React Routers navigate).
Breadcrumbs:
import { setBreadcrumbs, onBreadcrumbClick } from "@navikt/nav-dekoratoren-moduler";
setBreadcrumbs([ { title: "Ditt Nav", url: "https://www.nav.no/person/dittnav" }, { title: "Kontakt oss", url: "https://www.nav.no/person/kontakt-oss", handleInApp: true },]);
onBreadcrumbClick((breadcrumb) => { navigateTo(breadcrumb.url); // bytt med rammerverkets router});Språkvelger:
import { setAvailableLanguages, onLanguageSelect } from "@navikt/nav-dekoratoren-moduler";
setAvailableLanguages([ { locale: "nb", url: "https://www.nav.no/min-side/nb" }, { locale: "en", url: "https://www.nav.no/min-side/en", handleInApp: true },]);
onLanguageSelect((language) => { navigateTo(language.url);});⚠️ url er begrenset til nav.no og underdomener — andre URL-er gir 500-feil fra Dekoratøren.
CSP-header
import { buildCspHeader } from "@navikt/nav-dekoratoren-moduler/ssr";
const myAppDirectives = { "default-src": ["min-cdn.nav.no"], "style-src": ["css.nav.no"],};
const csp = await buildCspHeader(myAppDirectives, { env: "prod" });
// Express-eksempel:app.get("*", (req, res) => { res.setHeader("Content-Security-Policy", csp); // ...});Funksjonen slår automatisk sammen appens direktiver med Dekoratørens påkrevde direktiver.
Samtykke og cookies (ekomloven)
Fra 1. januar 2025 krever ekomloven samtykke før analyse og valgfrie cookies kan tas i bruk. Dekoratøren viser samtykkebanneret og håndterer lagring på tvers — moduler-pakken gir deg helpers for å etterleve dette i din app. Les mer om informasjonskapsler i Nav her.
import { awaitDecoratorData, isStorageKeyAllowed, setNavCookie, getNavCookie, navLocalStorage,} from "@navikt/nav-dekoratoren-moduler";
// Vent til Dekoratøren har lastet samtykke-dataawait awaitDecoratorData();
// Sjekk om en nøkkel er tillatt (uten å skrive)if (isStorageKeyAllowed("min-nøkkel")) { setNavCookie("min-nøkkel", "verdi");}
// navLocalStorage respekterer samtykke automatisknavLocalStorage.setItem("min-nøkkel", "verdi");| Funksjon | Forklaring |
|---|---|
| awaitDecoratorData() | Vent til samtykke er lastet |
| isStorageKeyAllowed(key) | Sjekk om nøkkel er tillatt å bruke |
| setNavCookie / getNavCookie | Les/skriv cookie med samtykke-sjekk |
| navLocalStorage / navSessionStorage | Storage-wrappers som respekterer samtykke |
Viktige parametre
| Parameter | Type | Default | Forklaring |
|---|---|---|---|
| context | privatperson / arbeidsgiver / samarbeidspartner | privatperson | Hvilken brukergruppe appen er for |
| language | nb / nn / en / se / pl / uk / ru | nb | Språk i dekoratøren |
| breadcrumbs | { title, url, handleInApp? }[] | [] | Brødsmulesti |
| availableLanguages | { locale, url, handleInApp? }[] | [] | Tilgjengelige språk i velgeren |
| simple | boolean | false | Forenklet header/footer uten meny |
| chatbot | boolean | true | Slå Frida-chatbot av/på |
| logoutWarning | boolean | true | Vis modal 5 min før token utløper |
| feedback | boolean | false | Vis tilbakemeldingswidget |
| redirectToApp | boolean | false | Redirect til appen etter innlogging |
Vanlige feil
| Problem | Årsak | Løsning |
|---|---|---|
| 403 ved npm install | Mangler PAT eller navikt SSO | Generer PAT med read:packages, aktiver navikt SSO |
| Dekoratøren vises ikke | Mangler access policy | Legg til nav-dekoratoren i accessPolicy.outbound.rules |
| Layout shift | CSR brukes istedenfor SSR | Bytt til fetchDecoratorReact |
| Cookie ikke satt | Samtykke ikke avventet | Bruk awaitDecoratorData() før setNavCookie |
| getAmplitudeInstance is not a function | Utdatert API (v4+) | Bytt til getAnalyticsInstance() |
Spørsmål? Ta kontakt i #dekoratøren_på_navno på Slack, eller les mer i Readme.
Forvalter