Skip to content

Instantly share code, notes, and snippets.

@rylanharper
Last active March 19, 2026 21:45
Show Gist options
  • Select an option

  • Save rylanharper/83db85fa82c854b7a2d0ca93d1ecbff9 to your computer and use it in GitHub Desktop.

Select an option

Save rylanharper/83db85fa82c854b7a2d0ca93d1ecbff9 to your computer and use it in GitHub Desktop.
Sanity + Nuxt3 + Nuxt Image(RC) → Using Blurhash & Lazysizes
_type == "picture" => {
_type,
"image": {
...,
"height": asset->metadata.dimensions.height,
"width": asset->metadata.dimensions.width,
"dimensions": asset->metadata.dimensions,
"blurhash": asset->metadata.blurHash,
"lqip": asset->metadata.lqip
}
}
import { ImageSquare } from 'phosphor-react'
export default {
title: 'Image',
name: 'picture',
type: 'image',
icon: ImageSquare,
options: {
hotspot: true,
metadata: ['lqip', 'blurhash']
},
fields: [
{
title: 'Alternative Text',
name: 'alt',
type: 'string',
description: 'A short description of the image. Important for SEO and accessiblity.',
validation: (Rule) => Rule.required()
}
],
preview: {
select: {
alt: 'alt',
filename: 'asset.originalFilename',
dimensions: 'asset.metadata.dimensions',
image: 'asset'
},
prepare({ alt, dimensions, filename, image }) {
return {
title: alt ?? filename,
subtitle: dimensions ? `${dimensions.width}px × ${dimensions.height}px` : '…',
media: image ?? ImageSquare
}
}
}
}
<script setup>
import { decode } from 'blurhash'
const props = defineProps({
image: {
type: Object,
default: undefined
}
})
const canvas = ref(null)
onMounted(() => {
if (!canvas.value) {
return
}
const pixels = decode(props.image.blurhash, 32, 32)
const imageData = new ImageData(pixels, 32, 32)
const context = canvas.value.getContext('2d')
context.putImageData(imageData, 0, 0)
})
const computedSizes = computed(() => {
const sizeVars = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl', '2xl', '3xl']
return sizeVars.map((size) => `${size}:100vw`).join(' ')
})
</script>
<template>
<figure
class="relative aspect-auto overflow-hidden"
:style="{ paddingTop: `${(props.image.height / props.image.width) * 100}%` }"
>
<canvas ref="canvas" class="absolute w-full h-full inset-0" width="32" height="32" />
<nuxt-img
:src="props.image.asset._ref"
:alt="props.image.alt"
:sizes="computedSizes"
:modifiers="{
crop: props.image.crop,
hotspot: props.image.hotspot
}"
loading="lazy"
class="absolute w-full h-full inset-0 lazyload"
/>
</figure>
</template>
<style scoped>
.lazyload,
.lazyloading {
opacity: 0;
}
.lazyloaded {
opacity: 1;
transition: opacity 0.3s ease;
transition-delay: 400ms;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment