Root > Articles > Tools >

How to use a custom theme with Dendron

Dec 26, 2021 • Yousef Amar • 4 min read


This is a quick write-up of how I themed the Dendron Next.js template. At time of writing, this information is up to date, however theming through a custom header may be possible by now, so please check. All the links to source code are to files under a specific commit, so line number may have changed also.

Creating a custom theme

Dendron uses for styling. On recommendation from Kevin Lin I used this generator to create my own.

The ant design docs have more information about customising here and I've also been using their default.less to figure out what the variables are called.

I created a custom-theme.less based on my default colour scheme and used these variables:

@primary-color: #e0d498;
@body-background: #030c22;
@link-color: #e0d498;
@link-decoration: none;
@heading-color: #e5e7e8;
@layout-header-background: #20293f;
@layout-sider-background: #030c22;
@text-color: #a9b0b3;
@text-color-secondary: #a9b0b3;
@disabled-color: rgba(0, 0, 0, 0.25);
@border-color-base: #a9b0b3;

Then I ran this command to generate the CSS using the dark theme as a base:

npx @emeks/antd-custom-theme-generator --theme dark vault/assets/styles/custom-theme.less vault/assets/styles/custom-theme.css

Now the way Dendron is currently set up, the built-in theme will always take precedence. So we need to suppress that in pages/_app.tsx:

@@ -12,7 +12,8 @@ import { useDendronGATracking } from "../components/DendronGATracking";
 import DendronLayout from "../components/DendronLayout";
 import { combinedStore, useCombinedDispatch } from "../features";
 import { browserEngineSlice } from "../features/engine";
-import "../public/assets-dendron/css/light.css";
+//import "../public/assets-dendron/css/light.css";
+import "../public/assets/styles/custom-theme.css";
 import "../styles/scss/main.scss";
 import { fetchConfig, fetchNotes } from "../utils/fetchers";
 import { useDendronRouter } from "../utils/hooks";
@@ -24,10 +25,11 @@ import { getLogLevel } from "../utils/etc";
 const themes = {
   dark: getAssetUrl(`/assets-dendron/css/dark.css`),
   light: getAssetUrl(`/assets-dendron/css/light.css`),
+  custom: getAssetUrl(`/assets/styles/custom-theme.css`),
 function AppContainer(appProps: AppProps) {
-  const defaultTheme = "light";
+  const defaultTheme = "custom";
   return (
     <Provider store={combinedStore}>
       <ThemeSwitcherProvider themeMap={themes} defaultTheme={defaultTheme}>

There are still loads of wrong colours

Unfortunately, there are some colours hardcoded in styles/scss/main.scss. So at the moment we can't help but modify that too. The relevant spots are are 1, 2, 3, 4, 5.

The wrong theme flashes briefly

This is due to styles/scss/base.scss which has some additional styling on top of the theme. There are colours in here which are defined in styles/scss/support/_variables.scss. This is entirely separate to the LESS variables. You can't use LESS variables in SCSS and vice versa of course (which is why there are so many hardcoded colours in main.scss too) so this is a bit of a problem.

I decided that actually the additions in base.scss aren't that important, so rather than mess around with it too much (e.g. by commenting out all the colours at least) I just commented out the whole @import "./base"; in main.scss.

If you did the above step, they will go away, since those special underlines are defines in base.scss. They're not the normal text-decoration so that gradients can be used. If you want to use base.scss, you can either comment that bit out (a:not([class])) or add the following to main.scss:

a {
  background: none !important;

Now there are ugly horizontal rules

I lied earlier -- not everything in base.scss is redundant. One part in there removed this weird ugly white border on hr elements. So I just added that back to main.scss since hr was being overridden there anyway:

hr {
   height: "1px";
+  border: none;

Additional sneaky hardcoded colours

Dark theme code syntax highlighting

For some reason, syntax highlighting never worked for me. I noticed that the class names followed PrismJS' conventions though, so I simply added PrismJS with dark theme to my header.html:

<link rel="stylesheet" href="">
<script src=""></script>
<script src=""></script>

I used the theme called tomorrow, because I thought it fit the nicest, but of course you can use any (or create your own).

In order to also have inline code like this look consistent, I added a little extra to main.scss using the same background colour as the tomorrow theme:

:not(pre) > code {
  background: #2d2d2d;
  padding: 1px 2px;

Other things I tweaked

Additional tweaks as of 2022-01-22

Future TODOs