The curious case of dark mode syntax highlighting

So I finally hacked in some dark mode support, only to run into another odd quirk: the syntax blocks wouldn’t change.

What gives? The various Nuxt module websites all have code examples that all switch beautifully to a dark theme when the system is in dark mode or the user switches to dark mode through a selector in the header, yet on my lil’ webpage things were broken.

How color modes are handled in Nuxt

The dark mode selector on the nuxt module websites are powered by @nuxtjs/color-mode. This relatively lightweight module effectively just keeps a class on the html element in sync the users device preference and offers a composable so you can change it in runtime. This allows you to do things like:

<script lang="ts" setup>
const colorMode = useColorMode();
</script>

<template>
    <div>
        <h1>Color mode: {{ $colorMode.value }}</h1>

        <select v-model="$colorMode.preference">
            <option value="system">System</option>
            <option value="light">Light</option>
            <option value="dark">Dark</option>
        </select>
    </div>
</template>

According to the docs, @nuxt/content’s syntax highlighting is natively compatible with this library. However.. this didn’t seem to be the case on my end.

Default values and when to ignore them

After no more than 15 minutes of reverse engineering, I realized all the previously mentioned Nuxt module websites have two things in common: they all use .dark on the html element rather than @nuxtjs/color-mode’s default .dark-mode, and they all use @nuxt/ui. Turns out @nuxt/content relies on the html class being called .dark to influence shiki’s theme. @nuxtjs/color-mode has an option classSuffix which is set to "-mode" by default, which in turn breaks the syntax highlighting from working properly.

So what’s the fix

Easiest workaround is to just set classSuffix back to "" in your nuxt.config.ts:

export default defineNuxtConfig({
    // ...
    colorMode: { classSuffix: "" },
});

This in turn makes the html class .dark, which makes it work with @nuxt/content’s usage of shiki.

Brief note on Nuxt UI

When you use Nuxt UI, it’s colorMode option allows you to opt-in to having @nuxtjs/color-mode available without having to install it as a separate module. This makes sense as @nuxt/ui’s pro version itself has some components included that rely on color mode being present, like ColorModeAvatar and ColorModeSwitch. However, when you opt-in to colorMode through @nuxt/ui, it actually overrides classSuffix back to "" on your behalf! This is why the Nuxt module websites and any other projects that use @nuxt/ui all work without a problem out of the box.


← Back to all posts