Skip to content

Instantly share code, notes, and snippets.

@gaurangrshah
Created December 5, 2020 18:37
Show Gist options
  • Save gaurangrshah/0d2a71f3f4ec8914063440f9954fe5db to your computer and use it in GitHub Desktop.
Save gaurangrshah/0d2a71f3f4ec8914063440f9954fe5db to your computer and use it in GitHub Desktop.
Integrate NextJs `next/image` with Chakra-UI styling
import { chakra, ThemingProps, useStyleConfig } from '@chakra-ui/react'
import NextImage, { ImageProps as NextImageProps } from 'next/image'
import { ReactElement } from 'react'
/**
* ? Because NextJs typing is preventing auto-suggest for layout, width and height
* ? we declare the styles differently in this component and will manage the switch
* ? to NextJs typings when calling NextJs Image component
*/
type LayoutValue = 'fixed' | 'intrinsic' | 'responsive' | undefined
type LayoutAndSize =
| {
layout: 'fill'
}
| {
layout: LayoutValue
height: number
width: number
}
/**
* Types for the Image component
* Picking only the props I want to allow, you can adjust to your liking
*/
type ImageProps = Pick<
NextImageProps,
'className' | 'loading' | 'objectFit' | 'objectPosition' | 'priority' | 'quality' | 'src' | 'unoptimized'
> &
Pick<Required<NextImageProps>, 'alt'> &
Pick<ThemingProps, 'variant'> & {
dimensions?: [number, number]
layout?: 'fill' | LayoutValue
}
/**
* Wrap NextJs Image component in Chakra's factory function
* This is what will allow to use the theme and the styling properties on the component
*/
const ImageWithChakra = chakra(
({
className,
dimensions = [0, 0],
layout = 'fill',
loading,
objectFit,
objectPosition,
priority,
quality,
src,
unoptimized,
...nextjsInternals
}: ImageProps): ReactElement => {
/**
* As explained earlier, NextJs typing is preventing auto-suggest for layout, width and height
* Here we actual convert our component typing to NextJs typing
*/
const [width, height] = dimensions
const layoutAndSize: LayoutAndSize =
height > 0 || width > 0
? {
height,
layout: layout === 'fill' ? 'intrinsic' : layout,
width
}
: {
layout: 'fill'
}
/**
* The actual NextImage component
*/
return (
<NextImage
className={className}
loading={loading}
objectFit={objectFit}
objectPosition={objectPosition}
priority={priority}
quality={quality}
src={src}
unoptimized={unoptimized}
{...layoutAndSize}
{...nextjsInternals}
/>
)
}
)
export const Image = ({ variant, ...props }: ImageProps): ReactElement => {
/**
* This components serves as an interface to pass Chakra's styles
* You can use the theme and/or styling properties (eg. backgroundColor='red.200')
*/
const styles = useStyleConfig('Image', { variant })
return <ImageWithChakra sx={styles} {...props} />
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment