How to Apply Dark Mode for Code Blocks in Next.js with Highlight.js and Tailwind CSS
We can use highlight.js to highlight code blocks in Next.js. However, it doesn't support dark mode by default, i.e. the code blocks will not change style when we switch to dark mode. My friend Songkeys provided a very elegant solution for this. In this article, I will show you how to apply dark mode for code blocks in Next.js with Tailwind CSS.
Install highlight.js and import code style
First, we need to install highlight.js.
1npm install highlight.js
After you install it, you can import any code style from highlight.js/styles/
to your project. For example, if you want to use the github-dark
style
You can import it in some tsx
file:
1import "highlight.js/styles/github-dark.css";
You can also import it in global.css
, if you turn on postcss-import
in your postcss.config.js
:
1module.exports = {2 plugins: {3 "postcss-import": {},4 tailwindcss: {},5 autoprefixer: {},6 },7};
1@import "highlight.js/styles/github-dark.css";
What is the problem for dark mode?
If you use github-dark
style, you will find that the code blocks will not change style when you switch to differnt modes (light or dark). Because you only import the github-dark
style.
Let's say what you want is to import github-dark.css
for dark mode and github.css
for light mode. How can you do that?
I used next-theme with attribute="class"
to switch between light and dark mode, which basically add a dark
or light
class to the html
tag when you switch to dark or light mode.
Therefore, to dynamically import css files for code blocks, you may considering about code like this:
1@import "highlight.js/styles/github.css";2.dark {3 @import "highlight.js/styles/github-dark.css";4}
However, this is not valid CSS. You can't use @import
inside a selector. From the MDN:
The
@import
CSS at-rule is used to import style rules from other validstylesheets. An@import
rule must be defined at the top of the stylesheet,before any other at-rule (except@charset
and@layer
) and styledeclarations, or it will be ignored.
Solution
For websites only support auto mode
If your website only support auto mode, which means the mode depends on the system preference, and visitors cannot switch between light and dark mode manually, you can use the following easy solution. (Notice to turn on postcss-import
in your postcss.config.js
)
1@import url("highlight.js/styles/github-dark.css") screen and2 (prefers-color-scheme: dark);3@import url("highlight.js/styles/github.css") screen and4 (prefers-color-scheme: light);
This solution is not valid for website support light, dark and auto mode. For example, visitors want dark mode and manually switch to it when their systems are in light mode, i.e. prefers-color-scheme: light
. Then the code block style will still be in light mode.
For websites support light, dark and auto mode
We can use SASS
/SCSS
to solve this problem. First, we need to install sass
in Next.js.
1npm install sass
Then, we change the global.css
to global.scss
and use the following code:
1@use "sass:meta";23@import "highlight.js/styles/github.css";4.dark {5 @include meta.load-css("highlight.js/styles/github-dark");6}
This code import github.css
by default. When you switch to dark mode, it will import github-dark.css
and override the style of github.css
. This is valid because SASS
support @include
inside a selector to import a css file.
Now, the code blocks will change style when you switch to dark mode. My website support light, dark and auto mode, it works very well.