Skip to content

Instantly share code, notes, and snippets.

@danieljpgo
Created July 12, 2024 14:43
Show Gist options
  • Save danieljpgo/44258925964f38cca9411dae7f713596 to your computer and use it in GitHub Desktop.
Save danieljpgo/44258925964f38cca9411dae7f713596 to your computer and use it in GitHub Desktop.
import { type ImageProps, getImageProps } from "next/image";
type DynamicImageProps = Omit<React.ComponentProps<"img">, "src"> & {
alt: string;
src: ImageProps["src"];
srcMobile: ImageProps["src"];
srcTablet: ImageProps["src"];
srcDesktop: ImageProps["src"];
priority?: ImageProps["priority"];
quality?: ImageProps["quality"];
placeholder?: ImageProps["placeholder"];
};
/**
* `<DynamicImage/>` should be used to render different images depending on the size of the viewport.
*
* To learn more:
*
* https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images#art_direction
*
* @example
* ```tsx
* return (
* <DynamicImage
* className="h-full w-full object-cover object-center"
* alt="alt description"
* src={imageDesktop}
* srcDesktop={imageDesktop}
* srcTablet={imageTablet}
* srcMobile={imageMobile}
* quality={100}
* priority
* />
* );
* ```
* If you do not have specific images for one of the viewport sizes, you can repeat the src:
* @example
* ```tsx
* return (
* <DynamicImage
* ...
* src={imageDesktop}
* srcDesktop={imageDesktop}
* srcTablet={imageDesktop}
* srcMobile={imageMobile}
* ...
* />
* );
* ```
*/
export function DynamicImage(props: DynamicImageProps) {
const {
alt,
srcMobile,
srcTablet,
srcDesktop,
quality,
priority,
placeholder,
...attrs
} = props;
const mobile = getImageProps({
quality,
priority,
alt,
placeholder,
src: srcMobile,
...(attrs.width && { width: Number(attrs.width) }),
...(attrs.height && { height: Number(attrs.height) }),
});
const tablet = getImageProps({
quality,
priority,
alt,
placeholder,
src: srcTablet,
...(attrs.width && { width: Number(attrs.width) }),
...(attrs.height && { height: Number(attrs.height) }),
});
const desktop = getImageProps({
quality,
priority,
alt,
placeholder,
src: srcDesktop,
...(attrs.width && { width: Number(attrs.width) }),
...(attrs.height && { height: Number(attrs.height) }),
});
return (
<picture>
<source media="(min-width: 1280px)" srcSet={desktop.props.srcSet} />
<source media="(min-width: 768px)" srcSet={tablet.props.srcSet} />
<source srcSet={mobile.props.srcSet} />
<img alt={alt} {...attrs} {...desktop.props} />
</picture>
);
}
// @TODO: document props
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment