How to dynamically change the theme using highlight.js?
Asked Answered
C

3

8

I have the following code:

<head>
    <title></title>
    <link rel="stylesheet" href="./styles/darkula.css">
    <link rel="stylesheet" href="./styles/github.css">
</head>
<body>
    <div class="container">
        <pre>
            <code class="html">
<button class="button is-primary">Primary</button>
            </code>
        </pre>
        <!-- Change theme button -->
        <button onclick="changeTheme()">Change theme</button>
    </div>
    <script src="highlight.pack.js"></script>
    <script>
        hljs.initHighlightingOnLoad();
        document.querySelectorAll("code").forEach(function(element) {
            element.innerHTML = element.innerHTML.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
        });

        function changeTheme() {
            ...
        }
    </script>
</body>

I am loading 2 themes in my file. Because the github theme is being loaded after the darkula theme, it gets applied to all the code elements automatically. This is fine, but I would like to allow users to dynamically change the theme to darkula with the click of the button. I could not find anything in the documentation. How can I do this?

Coldhearted answered 9/12, 2019 at 22:6 Comment(0)
L
7

If you are using sass/scss and handle your dependencies with npm, you can do the next thing:

@use "sass:meta";

html[data-theme="light"] {
  @include meta.load-css("highlight.js/styles/a11y-light");
}
html[data-theme="dark"] {
  @include meta.load-css("highlight.js/styles/a11y-dark");
}

To make it to work, you need to define the data-theme attribute in your html tag.

<html data-theme="light">
  <!-- ensure to change it with javascript and define one with default -->
  ...
</html>
Lomasi answered 6/3, 2022 at 15:14 Comment(0)
L
5

There's a github response to this same question here https://github.com/highlightjs/highlight.js/issues/2115

Basically you include all the themes you want, and then disable all the link tags except for the selected theme.

The highlight.js demo page does this https://highlightjs.org/demo/

The GitHub repository is for the code can be found here.

(https://github.com/highlightjs/highlight.js/blob/master/demo/demo.js)

Lashandralashar answered 28/1, 2020 at 9:20 Comment(0)
G
2

Here's a runnable snippet, to elaborate on the existing answers and provide a quick starter approach:

const themes = getThemes();
document.querySelector("span").textContent = themes[0];
hljs.highlightAll();

document.addEventListener("keydown", (event) => {
  if (event.key === "ArrowRight") {
    nextTheme();
    event.preventDefault();
  } else if (event.key === "ArrowLeft") {
    prevTheme();
    event.preventDefault();
  }
});

function prevTheme() {
  themes.unshift(themes.pop());
  changeTheme();
}

function nextTheme() {
  themes.push(themes.shift());
  changeTheme();
}

function changeTheme() {
  document.querySelector('link[href*="highlight.js"]').remove();
  const link = document.createElement("link");
  const theme = themes[0];
  link.rel = "stylesheet";
  link.href = `https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/${theme}.min.css`;
  document.querySelector("head").append(link);
  document.querySelector("span").textContent = theme;
}

function getThemes() {
return [
"a11y-dark",
"a11y-light",
"agate",
"an-old-hope",
"androidstudio",
"arduino-light",
"arta",
"ascetic",
"atom-one-dark-reasonable",
"atom-one-dark",
"atom-one-light",
"brown-paper",
"codepen-embed",
"color-brewer",
"dark",
"default",
"devibeans",
"docco",
"far",
"felipec",
"foundation",
"github-dark-dimmed",
"github-dark",
"github",
"gml",
"googlecode",
"gradient-dark",
"gradient-light",
"grayscale",
"hybrid",
"idea",
"intellij-light",
"ir-black",
"isbl-editor-dark",
"isbl-editor-light",
"kimbie-dark",
"kimbie-light",
"lightfair",
"lioshi",
"magula",
"mono-blue",
"monokai-sublime",
"monokai",
"night-owl",
"nnfx-dark",
"nnfx-light",
"nord",
"obsidian",
"panda-syntax-dark",
"panda-syntax-light",
"paraiso-dark",
"paraiso-light",
"pojoaque",
"purebasic",
"qtcreator-dark",
"qtcreator-light",
"rainbow",
"routeros",
"school-book",
"shades-of-purple",
"srcery",
"stackoverflow-dark",
"stackoverflow-light",
"sunburst",
"tokyo-night-dark",
"tokyo-night-light",
"tomorrow-night-blue",
"tomorrow-night-bright",
"vs",
"vs2015",
"xcode",
"xt256",
];
}
<meta name="color-scheme" content="dark light" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<link
  rel="stylesheet"
  href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/a11y-dark.min.css"
/>
<button type="button" onclick="prevTheme()">&lt;</button>
<button type="button" onclick="nextTheme()">&gt;</button>
<span></span>
<pre><code>{
  "web-app": {
    "servlet-name": "cofaxTools",
    "servlet-class": "org.cofax.cms.CofaxToolsServlet",
    "init-param": {
      "log": true,
      "logMaxSize": null,
      "dataLog": 1123
    }
  }
}</code></pre>

Basically, I rip out the existing style tag and replace it with the desired one. Crude, but effective.

Preloading the styles helps ensure smooth transitions, if desired.

Grownup answered 4/5 at 2:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.