12

I have an image with a white background, which looks off on docusaurus dark theme, so I want to detect when the user changes theme so I use a different image.

6 Answers6

12

If you are using the classic theme, you can leverage the useThemeContext hook to detect the current color mode setting. Since documents support MDX, you can create a component that conditionally displays the appropriate image based on the color mode value provided by the theme context. Here is a basic example.

This suggestion is based on using the following docusaurus versions:

>= @docusaurus/core@2.0.0-alpha.70 
>= @docusaurus/preset-classic@2.0.0-alpha.70

ImageSwitcher Component File

Create a react component that can be imported to your documentation

import React from 'react';
import useThemeContext from '@theme/hooks/useThemeContext'; //docs: https://v2.docusaurus.io/docs/2.0.0-alpha.69/theme-classic#usethemecontext

const ImageSwitcher = ({lightImageSrc, darkImageSrc}) => {
  const { isDarkTheme } = useThemeContext();

  return (
    <img src={isDarkTheme ? darkImageSrc : lightImageSrc} alt="Example banner" />
  )
}

export default ImageSwitcher;

Documentation Markdown File

Import the component into your documentation and pass the appropiate image sources to the component.

---
id: your-docs
title: Your Docs
---

import ImageSwitcher from '../../../src/ImageSwitcher.js';

<ImageSwitcher 
lightImageSrc="//satyr.io/300/black?text=LightMode"
darkImageSrc="//satyr.io/300/white?text=DarkMode"/>

Example Image Switcher Gif

GabLeRoux
  • 16,715
  • 16
  • 63
  • 81
br8dy
  • 121
  • 1
  • 5
  • I'm not able to replicate James' [issue below](https://stackoverflow.com/a/66130767/7168014) or reply to their comment. Both my development app and build work properly without errors. I'm guessing this may be a configuration difference. In my environment, the ImageSwitch component is a child of the Theme `` and it's provider. https://imgur.com/a/AWsatsl – br8dy Feb 10 '21 at 16:13
  • 4
    This was recently renamed to `useColorMode` in v2.0.0-beta15 as part of a larger refactor to use move `@theme/hooks` methods to `@docusaurus/theme-common`. See https://github.com/facebook/docusaurus/pull/6289 https://docusaurus.io/docs/2.0.0-beta.15/api/themes/configuration#use-color-mode – Erick Mar 09 '22 at 01:01
9

for version 2.0.0-beta.15, you can get current theme mode like this:

import { useColorMode } from '@docusaurus/theme-common';
// ^^ I don't think it's in the docs yet, but I get the referencet from here
// https://github.com/rohit-gohri/redocusaurus/issues/116

const Component = () => {
  const { isDarkTheme } = useColorMode();
  return <div>{isDarkTheme ? 'Dark' : 'Light'}</div>;
};
Alvin Novian
  • 181
  • 2
  • 5
3

Instead of creating a custom component, you can use Themed Images:

import ThemedImage from '@theme/ThemedImage';
import useBaseUrl from '@docusaurus/useBaseUrl';

<ThemedImage
  alt="Docusaurus themed image"
  sources={{
    light: useBaseUrl('/img/docusaurus_light.svg'),
    dark: useBaseUrl('/img/docusaurus_dark.svg'),
  }}
/>;

With it, you will not have the following error:

`useThemeContext` is used outside of `Layout` Component. 
Patitotective
  • 35
  • 1
  • 7
André Sousa
  • 1,692
  • 1
  • 12
  • 23
2

br8dy's answer above works in development-mode, but will throw an error when you try to build the project - Docusaurus will complain that the component doesn't exist within a component (displaying a reference to this part of the docs).

The solution is to use BrowserOnly, as documented here. Explicitly, you need to change this:

const ImageSwitcher = ({lightImageSrc, darkImageSrc}) => {
  const { isDarkTheme } = useThemeContext();

  return (
    <img src={isDarkTheme ? darkImageSrc : lightImageSrc} alt="Example banner" />
  )
}

To something like this:

const ImageSwitcher = ({lightImageSrc, darkImageSrc, altText}) => {
  return (
    <BrowserOnly fallback={<img src={darkImageSrc} alt={altText} />}>
      {() => {
        const { isDarkTheme } = useThemeContext();
        const imgSrc = isDarkTheme ? darkImgSrc : lightImgSrc;
        const fullImgSrc = useBaseUrl(imgSrc);

        return (
          <img src={fullImgSrc} alt={altText} />
        )
      }}
    </BrowserOnly>
  )
}
James
  • 1,394
  • 2
  • 21
  • 31
2

Now it is possible with the following, in a .mdx file:

import ThemedImage from '@theme/ThemedImage';

<ThemedImage
  alt="Docusaurus themed image"
  sources={{
    light: useBaseUrl('/img/docusaurus_light.svg'),
    dark: useBaseUrl('/img/docusaurus_dark.svg'),
  }}
/>;

Reference: Docusaurus. Themed images

D.Kastier
  • 2,640
  • 3
  • 25
  • 40
1

It sets attribute to html tag so you can check this attribute data-theme and listen to changes through MutationObserver.

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 31 '22 at 17:21