imagenext.jsmedia-queriesdarkmodenextjs-image

How can I present a different next/Image based on the user's preferred color scheme?


I'm trying to use a next/image instead of a regular img tag in the code below. With the regular <img> tag, the following achieves exactly what I'm looking for:

<div>
  <picture>
    <source
      srcSet="https://via.placeholder.com/100/333333/ffffff.png"
      media="(prefers-color-scheme: dark)"
    />
    <img
      src='https://via.placeholder.com/100/dddddd/000000.png'
      width='100px'
      height='100px'
      alt='Placeholder image'
    />
  </picture>
  <p>Change your OS or browser's preferred color scheme to see a different image.</p>
</div>

Indeed, when I set my OS (or browser) to the dark theme, I get a dark image, and vice-versa for the light theme.

However, if I try the same thing with a next/image, I just get the light-themed image every time… I can't put this into a snippet because next/image requires a Next.js server, but here is the code that I'm using, which, in my tests, is backed by a Next.js development server with the appropriate image-related settings configured in next.config.js:

// pages/test.js
import Image from 'next/image'

export default function MyWebPage () {
  return (
    <div>
      <picture>
        <source
          srcSet="https://via.placeholder.com/100/333333/ffffff.png"
          media="(prefers-color-scheme: dark)"
        />
        <Image src='https://via.placeholder.com/100/dddddd/000000.png' width='100px' height='100px' alt='Placeholder image' />
      </picture>
      <p>You can change your OS or browser's preferred color scheme, but you'll always see the light-theme image.</p>
    </div>
  )
}

Here I never get the dark-themed image, unfortunately.

Theories:

Question: How can I change the src of my next/image based on the user's preferred color scheme?


Non-solutions:


Solution

  • A bit late to the party, but had no issues using this within NextJs 13.

    // Relative import to your image file
    import MyLightImage from '../../../public/my-light-image.png';
    import MyDarkImage from '../../../public/my-dark-image.png';
    
    const MyImage = () => {
        return (
          <picture>
            <source srcSet={MyDarkImage.src} media="(prefers-color-scheme: dark)" />
            <Image
                src={MyLightImage}
                alt="My image"
                width={300}
                height={300}
            />
          </picture>
      );
    };
    
    export default MyImage;
    

    This would display MyImage for light theme and MyDarkImage for dark theme.