Skip to main content

Blur Loader with Cloudinary

Achieve 'Gatsby-like' Blur Loader using Cloudinary, and Next Image.

––– views

Blur loader I used throughout this website.

Inspired by Colby Fayock Blog Post.

CloudinaryImg Component

import { buildUrl } from 'cloudinary-build-url'; import clsx from 'clsx'; import Image from 'next/image'; import * as React from 'react'; import Lightbox from 'react-image-lightbox'; import 'react-image-lightbox/style.css'; type CloudinaryImgType = { publicId: string, height: string | number, width: string | number, alt: string, title?: string, className?: string, preview?: boolean, noStyle?: boolean, aspect?: { width: number, height: number, }, mdx?: boolean, } & React.ComponentPropsWithoutRef<'figure'>; export default function CloudinaryImg({ publicId, height, width, alt, title, className, preview = true, noStyle = false, mdx = false, style, aspect, ...rest }: CloudinaryImgType) { const [isOpen, setIsOpen] = React.useState < boolean > false; const urlBlurred = buildUrl(publicId, { cloud: { cloudName: 'theodorusclarence', }, transformations: { effect: { name: 'blur:1000', }, quality: 1, rawTransformation: aspect ? `c_fill,ar_${aspect.width}:${aspect.height},w_${width}` : undefined, }, }); const url = buildUrl(publicId, { cloud: { cloudName: 'theodorusclarence', }, transformations: { rawTransformation: aspect ? `c_fill,ar_${aspect.width}:${aspect.height},w_${width}` : undefined, }, }); const aspectRatio = aspect ? aspect.height / aspect.width : undefined; return ( <figure className={clsx(className, { 'overflow-hidden rounded shadow-sm dark:shadow-none': !noStyle, 'mx-auto': mdx && width <= 800, })} style={{ ...(mdx && width <= 800 ? { maxWidth: width } : {}), ...style, }} {...rest} > <div style={{ position: 'relative', height: 0, paddingTop: aspectRatio ? `${aspectRatio * 100}%` : `${(+height / +width) * 100}%`, cursor: preview ? 'zoom-in' : 'default', }} className='img-blur' onClick={preview ? () => setIsOpen(true) : undefined} > <style jsx>{` .img-blur::before { content: ''; position: absolute; inset: 0; filter: blur(20px); z-index: 0; background-image: url(${urlBlurred}); background-position: center center; background-size: 100%; } `}</style> <div className='absolute top-0 left-0'> <Image width={width} height={height} src={url} alt={alt} title={title || alt} /> </div> </div> {isOpen && ( <Lightbox mainSrc={url} onCloseRequest={() => setIsOpen(false)} /> )} </figure> ); }
jsx

Usage

1. For full width

<figure className='overflow-hidden rounded-sm shadow-md dark:shadow-none'> <CloudinaryImg publicId='theodorusclarence/cloudinaryId.jpg' width='1440' height='792' alt='Your alt text' /> </figure>
jsx

2. For specified width and centered

If not using jit or in mdx, width can be replaced by using inline-style

<figure className='w-[210px] mx-auto shadow-md dark:shadow-none'> <CloudinaryImg publicId='theodorusclarence/cloudinaryId.png' width='210' height='149' alt='Your alt text' /> </figure>
jsx