Kom i gang som utvikler

Designsystemet Punkt skal hjelpe deg som utvikler i Oslo kommune å komme raskt i gang med å bygge digitale løsninger som følger Oslo kommunes visuelle identitet og som er universelt utformet.

Koden til Punkt er delt opp i ulike pakker:

Minstekravet for å komme igang med Punkt er å installere assets og css. Deretter kan du velge om du trenger elements eller react.

assets, css og elements kan brukes fra vår CDN uten noen byggesteg, og det ønskes. Men de fleste velger å installere pakkene inn i sitt prosjekt. Se egne CDN-instrukser dersom du ønsker å bruke Punkt fra CDN. Alle andre instrukser forutsetter at du laster ned våre pakker fra NPM.

Utviklere og Figma

Designsystemet Punkt leveres også som et bibliotek i designverktøyet Figma. I tverfaglige team er det naturlig at utviklere og designere jobber tett sammen også i designprosessen. Vi anbefaler at alle utviklere har tilgang til Punkt i Figma.

Informasjon om Figma og tilganger

CSS og assets

Punkt CSS er basert på Sass, og for å få mest mulig utbytte av våre stilsett anbefaler vi at dere bruker SCSS-filene våre fremfor de genererte CSS-filene.

Start med å legge til de nødvendige pakker i prosjektet ditt:

npm add -D sass
npm add @oslokommune/punkt-assets
npm add @oslokommune/punkt-css

Deretter kan du inkludere Punkt i hoved-stilsettet ditt:

/* Overstyr stien til fontene. */
@use '@oslokommune/punkt-css/dist/scss/abstracts/variables' with (
  $font-path: '@oslokommune/punkt-assets/dist'
);

/* Hent inn Punkts stiler */
@use '@oslokommune/punkt-css/dist/scss/pkt';

/* Responsive spacing-klasser, som mb-size-24--tablet-up. Optional. */
@use '@oslokommune/punkt-css/dist/scss/pkt-spacing-responsive';

De responsive spacing-klassene ligger i en egen fil fordi de var over halvparten av reglene i pkt-base og nesten ingen bruker dem. Trenger du dem ikke kan du droppe den linja. Se Spacing.

Og vips er du i gang! Det er mulig du må fjerne noen av dine lokale stiler (f.eks. font-family) dersom de krasjer med Punkt.

Les mer om verktøyene og hjelpeklassene våre under de forskjellige Ressurser-sidene.

Bruk av CSS @layer

Legger du Punkt i et eget @layer, kan du overstyre stilene våre uten å gjøre selektorene dine mer spesifikke.

Med SCSS

Bruk pkt.layer i stedet for pkt. Alt annet er som før:

/* Overstyr stien til fontene. */
@use '@oslokommune/punkt-css/dist/scss/abstracts/variables' with (
  $font-path: '@oslokommune/punkt-assets/dist'
);

/* Hent inn Punkts stiler, pakket i @layer punkt */
@use '@oslokommune/punkt-css/dist/scss/pkt.layer';

@layer app {
  .min-komponent {
    color: red;
  }
}

Nå vinner .min-komponent over Punkt-stilene, uansett hvor spesifikke våre selektorer er.

Med ren CSS

Henter du CSS-en fra CDN-en, legg Punkt i ett layer og dine egne stiler i et layer etter. Husk å åpne for CDN-domenet i CSP-en din, se CSP-seksjonen.

@layer punkt, app;

@import url('https://punkt-cdn.oslo.kommune.no/19/css/pkt.min.css') layer(punkt);

@layer app {
  .min-komponent {
    color: red;
  }
}

Rekkefølgen i @layer punkt, app; bestemmer hvem som vinner: det layer som står sist, vinner over det layer som står før. Stiler du skriver uten layer, vinner over alle layers.

Trenger du bare deler av Punkt, kan du importere flere filer inn i samme layer. Behold rekkefølgen under, den er den samme som i pkt.min.css:

@layer punkt, app;

@import url('https://punkt-cdn.oslo.kommune.no/19/css/pkt-normalise.min.css') layer(punkt);
@import url('https://punkt-cdn.oslo.kommune.no/19/css/pkt-base.min.css') layer(punkt);
@import url('https://punkt-cdn.oslo.kommune.no/19/css/pkt-spacing-responsive.min.css') layer(punkt);
@import url('https://punkt-cdn.oslo.kommune.no/19/css/pkt-elements.min.css') layer(punkt);
@import url('https://punkt-cdn.oslo.kommune.no/19/css/pkt-components.min.css') layer(punkt);
Legg hele Punkt i samme layer

Fordeler du Punkt-filene i flere layers, eller lar noen av dem ligge uten layer, begynner stilene våre å konkurrere med hverandre. Da kan for eksempel lenkestilene i pkt-base vinne over knappestilene i pkt-components. Bruk ett layer for hele Punkt.

React

Vær oppmerksom på at Punkt React er avhengig av Punkt CSS. Komponentene er ren React og bruker ikke Punkt Elements.

For å installere Punkt React:

npm add @oslokommune/punkt-react

Det er alt du strengt tatt trenger å gjøre. For instrukser om hvordan du tar i bruk komponentene og hva du kan gjøre med dem kan du lese på de enkelte komponenters dokumentasjonssider.

Eksempel:

import { PktButton, PktTextinput } from "@oslokommune/punkt-react";
...
<PktTextinput label="First name" id="firstName" />
<PktButton skin="primary" variant="icon-left" iconName="user">
	Testbutton
</PktButton>

OBS: Våre React-komponenter bruker ikoner og ressurser fra vår CDN. Dersom du bruker en Content Security Policy (CSP) må du åpne for å hente ressurser fra https://punkt-cdn.oslo.kommune.no/. Se CSP-seksjonen for detaljer.

Byggeverktøy som Vite og webpack tar bare med komponentene du faktisk importerer.

Next.js (App Router)

Komponentene kan importeres rett i Server Components. Komponenter som bare viser innhold, som PktTable, PktHeading og PktLink, rendres på serveren. Resten er klientkomponenter.

Bygger du med webpack (standard i Next.js 15, next build --webpack i Next.js 16), må du legge til pakken i optimizePackageImports. Ellers blir alle komponentene med i klientbundelen når du importerer fra en Server Component, også de du ikke bruker. Turbopack (standard i Next.js 16) og Pages Router trenger ikke dette.

// next.config.mjs
export default {
  experimental: {
    optimizePackageImports: ['@oslokommune/punkt-react'],
  },
}

Bruker du jsdom i enhetstestene dine, trenger noen komponenter litt tilrettelegging. PktModal bruker for eksempel <dialog>, som jsdom ikke støtter. Se avsnittene om testing i dokumentasjonen til den enkelte komponenten.

Elements

Punkt Elements er våre komponenter som er bygger på web components-teknologi. Det betyr at de kan tas i bruk i alle frontendrammeverk og til og med rett i HTML.

For å installere komponentene:

npm add @oslokommune/punkt-elements

Og deretter kan du finne instrukser for hver komponent under “Implementasjon i kode” på komponentens dokumentasjonsside.

Eksempel:

import @oslokommune/punkt-elements/dist/pkt-textinput.js;
import @oslokommune/punkt-elements/dist/pkt-button.js;
<pkt-textinput label="Fornavn" name="fornavn"></pkt-textinput>
<pkt-button type="submit">Dette er en knapp</pkt-button>

Innholdet i komponentene kan endres etter at de er vist, for eksempel fra Vue eller med vanlige DOM-metoder som appendChild og textContent. Har du flere elementer i samme komponent, for eksempel en liste, anbefaler vi å pakke dem inn i ett element, som en div eller ul. Da holder komponenten styr på ett element i stedet for mange, og oppdateringer går mye raskere.

CDN

Dersom du ønsker å ta i bruk CSS, ressurser og Elements-komponenter fra CDN kan det enkelt gjøres ved å inkludere disse rett inn i prosjektet ditt. Vær dog oppmerksom på at dersom du bruker CSP kan du støte på utfordringer. Se CSP-seksjonen for hvordan du konfigurerer dette.

Vi anbefaler å enkelt og greit inkludere hele CSS-rammeverket vårt, men om du heller vil velge ut hva du ønsker å inkludere kan du finne rett fil ved å lete i vår CDN.

Her er et eksempel på hvordan du kan ta i bruk Punkt i en ren HTML-side:

<!doctype html>
<html lang="no">
  <head>
    <meta charset="utf-8" />
    <title>Punkt</title>
    <link href="https://punkt-cdn.oslo.kommune.no/19/css/pkt.min.css" rel="stylesheet" />
    <!-- Bare hvis du bruker responsive spacing-klasser, som mb-size-24--tablet-up -->
    <link href="https://punkt-cdn.oslo.kommune.no/19/css/pkt-spacing-responsive.min.css" rel="stylesheet" />
    <script src="https://punkt-cdn.oslo.kommune.no/19/elements/pkt-consent.js" type="module"></script>
  </head>
  <body>
    <pkt-consent
      id="osloConsent"
      triggerType="link"
      triggerText="Åpne samtykkemodal"
      devMode
    ></pkt-consent>
    <script>
      const consent = document.querySelector('#osloConsent')
      consent.addEventListener('toggle-consent', (event) => {
        console.log(event.detail)
      })
    </script>
  </body>
</html>

Content Security Policy (CSP)

Dersom applikasjonen din bruker en Content Security Policy, må du åpne for ressurser fra Punkt sin CDN. Punkt henter fonter, ikoner (SVG), stilsett og scripts fra https://punkt-cdn.oslo.kommune.no/, og dette gjelder uansett om du installerer via NPM eller bruker CDN direkte.

Legg til følgende direktiver i din CSP:

Content-Security-Policy:
  default-src 'self';
  font-src 'self' https://punkt-cdn.oslo.kommune.no/;
  img-src 'self' https://punkt-cdn.oslo.kommune.no/ blob:;
  script-src 'self' https://punkt-cdn.oslo.kommune.no/;
  style-src 'self' 'unsafe-inline' https://punkt-cdn.oslo.kommune.no/;
  connect-src 'self' https://punkt-cdn.oslo.kommune.no/;

Dersom du setter CSP via en <meta>-tag i HTML:

<meta
  http-equiv="Content-Security-Policy"
  content="default-src 'self'; font-src 'self' https://punkt-cdn.oslo.kommune.no/; img-src 'self' https://punkt-cdn.oslo.kommune.no/ blob:; script-src 'self' https://punkt-cdn.oslo.kommune.no/; style-src 'self' 'unsafe-inline' https://punkt-cdn.oslo.kommune.no/; connect-src 'self' https://punkt-cdn.oslo.kommune.no/;"
/>
Bruker du Consent, global header eller footer?

Disse komponentene henter i tillegg innhold fra https://cdn.web.oslo.kommune.no/ og trenger egne tillatelser:

  • Global header og footer henter meny- og footerinnhold fra endepunktet — legg til domenet iconnect-src.

  • Consent laster script og stilark fra samme CDN — legg til domenet i script-src og style-src.

  • Søket i global header sender en GET-form til https://www.oslo.kommune.no/ — bruker du form-action-direktivet, må søkemålet også tillates.

Se CSP-avsnittene på komponentsidene for header, footer og consent for detaljer og alternativer (blant annet server-side henting via data-propen).

Hvorfor `blob:` i `img-src`?

Enkelte komponenter (for eksempel PktFileUpload med miniatyrvisning) forhåndsviser lokale filer ved å bruke midlertidige blob:-URLer i nettleseren. Uten blob: i img-src kan slike bilder bli blokkert i produksjon.

Vi anbefaler å holde dette strengt avgrenset til img-src. Du skal normalt ikke legge blob: til i script-src.

Hvorfor unsafe-inline?

På grunn av SVG-styling og visse web component-funksjoner krever Punkt ‘unsafe-inline’ istyle-src-direktivet. Uten dette vil noen stiler bli blokkert av nettleseren. Dersom du ønsker å unngå ‘unsafe-inline’ kan du bruke CSP-nonces, men dette krever server-side konfigurasjon.

DirektivHva det dekker
font-srcFonter (.woff, .woff2)
img-srcBilder og SVG-ikoner (inkludert lokale forhåndsvisninger via blob:)
script-srcJavaScript-filer (Elements-komponenter fra CDN)
style-srcCSS-stilsett og inline-stiler
connect-srcFetch/XHR-forespørsler (f.eks. dynamisk lasting av SVG-ikoner)

Trenger du hjelp?

Dersom du støter på noen problemer eller utfordringer må du ikke nøle med å ta kontakt med oss! Den enkleste måten å få kontakt med oss er på Slack-kanalen vår, men vi har også en epost-adresse du kan nå oss på: punkt@dig.oslo.kommune.no.