Hopp til innhold

Maler

Temabytte

NyOppdatert 27. januar 2026

Retningslinjer og tips til hvordan du kan støtte temabytte i appen din.

Eksempler

Bruk av mørkt tema

For åpne sider under Nav.no skal det kordineres med Nav.no-teamet om løsninger skal kunne støtte noen annet en lyst tema. Til dags dato (28.01.26) er det ikke opprettet en strategi for dette.

Hvis appen er en underside eller del av et større system, må temabytte være konsistent på tvers av hele systemet.

Potensielle fallgruver

Før du støtter bruk av mørkt fargetema bør du ta en gjennomgang av løsningen din

  • Bruker løsningen noen “widgets”, f.eks tredjeparts-innhold som tilbakemelding-popups etc. Hvordan støtter disse mørkt tema?
  • Tar løsningen i bruk noen iframes? Om så, hvordan løses temabytte på tvers.
  • Bruker løsningen mye illustrasjoner, bilder eller annen media? Må disse oppdateres til å endres på tvers av tema?

Automatisk tema (prefers-color-scheme)

Forhåndsvalgt tema bør følge brukerens systeminnstilling, men må kunne overstyres. Dette kan hentes ut med window.matchMedia("(prefers-color-scheme: dark)").matches.

Nextjs

For next så vil pakker som next-themes være den enkleste metoden for å håndtere temabytte.

NextThemeProvider.tsx
import { ThemeProvider as NextThemeProvider } from "next-themes";
function ThemeProvider({ children }: { children: React.ReactNode }) {
return (
<NextThemeProvider
attribute="class"
>
{children}
</NextThemeProvider>
);
}

SPA

SPAThemeProvider.tsx
import { createContext, useContext, useEffect, useState } from "react"
type Theme = "dark" | "light" | "system"
type ThemeProviderProps = {
children: React.ReactNode
defaultTheme?: Theme
storageKey?: string
}
type ThemeProviderState = {
theme: Theme
setTheme: (theme: Theme) => void
}
const initialState: ThemeProviderState = {
theme: "system",
setTheme: () => null,
}
const ThemeProviderContext = createContext<ThemeProviderState>(initialState)
export function ThemeProvider({
children,
defaultTheme = "system",
storageKey = "spa-theme",
...props
}: ThemeProviderProps) {
const [theme, setTheme] = useState<Theme>(
() => (localStorage.getItem(storageKey) as Theme) || defaultTheme
)
useEffect(() => {
const root = window.document.documentElement
root.classList.remove("light", "dark")
if (theme === "system") {
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
.matches
? "dark"
: "light"
root.classList.add(systemTheme)
return
}
root.classList.add(theme)
}, [theme])
const value = {
theme,
setTheme: (theme: Theme) => {
localStorage.setItem(storageKey, theme)
setTheme(theme)
},
}
return (
<ThemeProviderContext.Provider {...props} value={value}>
{children}
</ThemeProviderContext.Provider>
)
}
export const useTheme = () => {
const context = useContext(ThemeProviderContext)
if (context === undefined)
throw new Error("useTheme must be used within a ThemeProvider")
return context
}
App.tsx
import { ThemeProvider } from "@/components/theme-provider"
function App() {
return (
<ThemeProvider defaultTheme="light" storageKey="spa-theme">
{children}
</ThemeProvider>
)
}
export default App