Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add light/dark mode theme detection to image component example #53760

36 changes: 36 additions & 0 deletions docs/02-app/02-api-reference/01-components/image.mdx
Expand Up @@ -725,6 +725,42 @@ Try it out:

- [Demo the `fill` prop](https://image-component.nextjs.gallery/fill)

## Theme Detection

If you want to display a different image for light mode vs dark mode, you can create a new component that wraps two `<Image>` components and reveals the correct one based on a CSS media query.
styfle marked this conversation as resolved.
Show resolved Hide resolved

```css filename="components/theme-image.module.css"
.imgDark {
display: none;
}

@media (prefers-color-scheme: dark) {
.imgLight {
display: none;
}
.imgDark {
display: unset;
}
}
```

```jsx filename="components/theme-image.js"
leerob marked this conversation as resolved.
Show resolved Hide resolved
import styles from './theme-image.module.css'
const ThemeImage = (props) => {
const { srcLight, srcDark, ...rest } = props
return (
<>
<Image {...rest} src={srcLight} className={styles.imgLight} />
<Image {...rest} src={srcDark} className={styles.imgDark} />
</>
)
}
```

> **Good to know**: This depends on the default behavior of `loading="lazy"` so that only the correct image is loaded. You cannot use `priority` or `loading="eager"` because it could cause both images to load.
styfle marked this conversation as resolved.
Show resolved Hide resolved

- [Demo light/Dark mode theme detection](https://image-component.nextjs.gallery/theme)
styfle marked this conversation as resolved.
Show resolved Hide resolved

## Known Browser Bugs

This `next/image` component uses browser native [lazy loading](https://caniuse.com/loading-lazy-attr), which may fallback to eager loading for older browsers before Safari 15.4. When using the blur-up placeholder, older browsers before Safari 12 will fallback to empty placeholder. When using styles with `width`/`height` of `auto`, it is possible to cause [Layout Shift](https://web.dev/cls/) on older browsers before Safari 15 that don't [preserve the aspect ratio](https://caniuse.com/mdn-html_elements_img_aspect_ratio_computed_from_attributes). For more details, see [this MDN video](https://www.youtube.com/watch?v=4-d_SoCHeWE).
Expand Down
3 changes: 3 additions & 0 deletions examples/image-component/pages/index.tsx
Expand Up @@ -50,6 +50,9 @@ const Index = () => (
<li>
<Link href="/color">Color placeholder</Link>
</li>
<li>
<Link href="/theme">Light/Dark mode theme detection</Link>
</li>
<li>
<Link href="/background">Text on background image</Link>
</li>
Expand Down
38 changes: 38 additions & 0 deletions examples/image-component/pages/theme.tsx
@@ -0,0 +1,38 @@
import Image, { ImageProps } from 'next/image'
import ViewSource from '../components/view-source'
import styles from '../styles.module.css'

// Note: we cannot use `priority` or `loading="eager"
// because we depend on the default `loading="lazy"`
// behavior to wait for CSS to reveal the proper image.
type Props = Omit<ImageProps, 'src' | 'priority' | 'loading'> & {
srcLight: string
srcDark: string
}

const ThemeImage = (props: Props) => {
const { srcLight, srcDark, ...rest } = props

return (
<>
<Image {...rest} src={srcLight} className={styles.imgLight} />
<Image {...rest} src={srcDark} className={styles.imgDark} />
</>
)
}

const Page = () => (
<div>
<ViewSource pathname="pages/theme.tsx" />
<h1>Image With Light/Dark Theme Detection</h1>
<ThemeImage
alt="Next.js Streaming"
srcLight="https://assets.vercel.com/image/upload/front/nextjs/streaming-light.png"
srcDark="https://assets.vercel.com/image/upload/front/nextjs/streaming-dark.png"
width={588}
height={387}
/>
</div>
)

export default Page
14 changes: 14 additions & 0 deletions examples/image-component/styles.module.css
Expand Up @@ -48,3 +48,17 @@
padding-top: 40vh;
text-shadow: 1px 1px 1px #3c5c5e;
}

.imgDark {
display: none;
}

@media (prefers-color-scheme: dark) {
.imgLight {
display: none;
}

.imgDark {
display: unset;
}
}