Theming & Dark Mode

Dark mode toggles Bootstrap 5.3's data-bs-theme on <html>, persisted under localStorage['lte-theme']. Under Nuxt a blocking inline head script applies the stored preference before first paint, so there's no flash of the wrong theme on SSR.

The color-mode composable

<LteDashboardLayout> calls provideColorMode internally, so any descendant can read and set the theme with useColorMode():

<script setup lang="ts">
const { colorMode, resolvedMode, setColorMode } = useColorMode()
//      ColorMode      ResolvedColorMode   (mode) => void
</script>

<template>
  <button @click="setColorMode('light')">Light</button>
  <button @click="setColorMode('dark')">Dark</button>
  <button @click="setColorMode('auto')">Auto</button>
  <p>Resolved theme: {{ resolvedMode }}</p>
</template>
MemberTypePurpose
colorModeRef<'light' | 'dark' | 'auto'>The user's chosen mode.
resolvedModeComputedRef<'light' | 'dark'>The concrete theme after auto is evaluated against the OS.
setColorMode(mode)(ColorMode) => voidSwitch the mode; the new value is persisted and applied.

How it stays in sync

  • The preference lives under localStorage['lte-theme'] — the same key shared with the React, Symfony and Angular ports.
  • The initial fallback comes from initialColorMode (layout prop) or the Nuxt module's defaults.initialColorMode.
  • On auto, the composable tracks prefers-color-scheme via a matchMedia listener and re-resolves when the OS theme changes.
  • Every access to window / document / localStorage is SSR-guarded, so it's safe to call during server render.

The toggle component

Drop <LteColorModeToggle> anywhere inside the layout (it is already in the default <LteTopbar>) for a light/dark/auto switcher:

<LteColorModeToggle />

SSR-safe theming (Nuxt)

The @adminlte/nuxt module injects a tiny blocking head script (controlled by the themeScript option) that runs before anything renders. It reads the stored value (falling back to your initialColorMode), resolves auto against the OS, and sets data-bs-theme on <html> — eliminating the flash entirely. The composable then owns all reactive updates after hydration.

In plain Vue (no Nuxt) there is no blocking head script: the composable applies the theme in onMounted. If you SSR your own Vue app, add an equivalent inline script in your HTML template that reads localStorage['lte-theme'] and sets data-bs-theme before paint.

Customizing colors

AdminLTE 4 is built on Bootstrap 5.3 CSS variables, so override theme colors with standard Bootstrap custom properties — scoped to a theme where needed:

:root {
  --bs-primary: #6610f2;
  --bs-primary-rgb: 102, 16, 242;
}
[data-bs-theme="dark"] {
  --bs-body-bg: #14181f;
}

Import these after @adminlte/vue/css so your overrides win. The library ships both an LTR stylesheet (@adminlte/vue/css) and an RTL build (@adminlte/vue/css/rtl); set dir="rtl" on the layout to use the latter.

Because the theme is set on <html> before the body paints, your overrides must be valid for both [data-bs-theme="light"] and [data-bs-theme="dark"] to avoid a mismatch when users switch.


AdminLTE 4 · Vue port Edit on GitHub