How does CM6 decide whether dark mode is on/off?

I’m looking to improve user experience of people that use my website in dark mode.

I’ve looked through documentation and I found a few pieces of information about dark mode, but not what I was looking for.

CM6 has &dark and &light placeholders that can be used to change styles based on whether the website is in dark or light mode. How does CM6 decide that? Does it simply look at window.matchMedia('(prefers-color-scheme: dark)')?

I’d like to be more flexible than that. I offer my users to switch between themes with three options: auto/light/dark. Auto observes the OS-level setting. Light and dark always use their respective themes.

I’d like to persuade CM6 about user-overriden light and dark themes. Is it possible?

Per TailwindCSS instructions (Dark Mode - Tailwind CSS) I’m using the “selector” strategy which observes whether the html tag has “dark” class or not. I’d like CM6 to follow that.


This is determined by the dark option of the active theme. The library itself does no detection of prefers-color-scheme.

If you want something dumb/simple I use the onedark theme and conditionally spread it into my extensions. The theme value comes from here, and I use a mutation observer to watch for changes. If you look at the sqlite box here and toggle your system theme, it should switch.

I’m sorry, but this makes me even more confused than before. What if I’m using EditorView.baseTheme() and not EditorView.theme()? How can I define if the theme is dark or not?

What if I pass multiple EditorView.theme() to the extensions list while creating the editor, some with dark: false and others with dark: true?

If you’re not using a theme, you get the &light base theme rules. If any of the themes you’re using set the editor to dark, you get &dark.

I’m trying to set this up but I have problems reconfiguring the theme using a compartment.

I made a short example: Try CodeMirror

On load, randomly the dark is set to true or false, which can be seen on how the gutter looks. After a few reloads (or clicking on Run), the gutter should change its appearance.

Additionally, I’m changing the “dark” value every second and reconfiguring the theme with a compartment, but that doesn’t do anything. My expectation is that the gutter would change every second to the other appearance.

Oh, I figured it out, I just forgot “reconfigure” returns an effect we have to dispatch: Try CodeMirror

You may find it easier to define a highlight style, e.g. depending on your syntax, something along the lines of:

const highlightStyle = HighlightStyle.define([
  { tag: tags.atom,      class: 'cmt-atom'      },
  { tag: tags.comment,   class: 'cmt-comment'   },
  { tag: tags.keyword,   class: 'cmt-keyword'   },
  { tag: tags.literal,   class: 'cmt-literal'   },
  { tag:,      class: 'cmt-name'      },
  { tag: tags.number,    class: 'cmt-number'    },
  { tag: tags.operator,  class: 'cmt-operator'  },
  { tag: tags.separator, class: 'cmt-separator' },
  { tag: tags.string,    class: 'cmt-string'    }

Then use it in your editor via syntaxHighlighting(highlightStyle).

With that in place, you can then define classes in CSS as usual, and use prefers-color-scheme there to handle light and dark modes, which, at least in my case, tend to follow the sun on a phone, so the light / dark mode is dynamic. Trivial to handle in CSS, relatively hard elsewhere.