Hoppa till huvudinnehåll

Using Bootstrap 5 dark color theme in Vue 3

Inlagt av Arild Matsson 2025-11-14

The new Vue 3 version of Korp will probably be using Bootstrap 5. I was just looking into how to implement dark mode in that setup. Here’s what I came up with.

Bootstrap dark color theme

Bootstrap (5.3 and above) includes a dark theme. It does not detect the user’s preference by default, but instead relies on the developer to set it explicitly with the data-bs-theme attribute.

I think having it opt-in makes sense, because ensuring a pretty and accessible user interface in multiple color themes adds a significant burden on development. Even if Bootstrap provides all the basic styles, you may still need to maintain custom things like charts and logos.

<!-- Light mode: -->
<html>

<!-- Dark mode: -->
<html data-bs-theme="dark">

I just wish it would also allow data-bs-theme="auto". But instead, we have to…

Detect user preference with VueUse

To me, VueUse is more or less a necessary dependency for any Vue 3 project. One of all its features is the useDark() function which helps to manage dark mode in four ways: it detects system preference, syncs with local storage and, of course, provides the value as a ref. Lastly, and this I discovered today, it syncs with an HTML attribute. By default, it uses <html class="dark">, but it can be configured to work with Bootstrap’s <html data-bs-theme="dark">.

// App.vue
import { useDark } from "@vueuse/core"

useDark({ attribute: "data-bs-theme" })

This will detect system-level dark mode and set the HTML attribute accordingly, which in turn will enable Bootstrap’s built-in dark styles.

Alternative: native JavaScript

In case you are not using VueUse (or even Vue), you should be able to get the same effect using matchMedia():

if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
  document.documentElement.dataset.bsTheme = "dark"
}

You can also listen to the MediaQueryList object returned by it. That’s essentially what VueUse wraps around anyway.

Prevent white flicker

When loading the page with dark mode enabled on the system level, the browser will show its default white background for a short time. Only after the styles and scripts have been loaded, they will detect and apply the dark theme like described.

To prevent this flicker, we need to override the default background as soon as possible, already in index.html:

<head>
  ...
  <style type="text/css">
    /* Avoid white background being default until VueUse/Bootstrap notices dark mode. */
    @media (prefers-color-scheme: dark) {
      :root:not([data-bs-theme]) body {
        background-color: #212529;
      }
    }
  </style>
</head>