Magic Image is a Nuxt module that combines Nuxt Image and Unlazy into a single component. Reach for it whenever an image should carry a responsive srcset and lazy load itself without per-image wiring: content images, hero art, CMS media, Mux video thumbnails.
- Auto lazy loading – Native lazy loading via Unlazy with SSR placeholder support
- Responsive srcsets – Automatic multi-size srcset generation via Nuxt Image
- Built-in providers – MaaS image CDN and Mux video thumbnail extraction out of the box
- Typed modifiers – Full TypeScript types for all provider-specific modifier options
<template>
<magic-image
src="https://images.unsplash.com/photo-1694444070793-13db645409f4"
:modifiers="{ width: 800, height: 600, fit: 'cover' }"
/>
</template>The component is registered globally. No import needed.
Add @maas/magic-image and its two peer dependencies to your dependencies.
# pnpm
pnpm add @maas/magic-image @nuxt/image @unlazy/nuxt
# npm
npm install @maas/magic-image @nuxt/image @unlazy/nuxt
# yarn
yarn add @maas/magic-image @nuxt/image @unlazy/nuxt
# bun
bun add @maas/magic-image @nuxt/image @unlazy/nuxtNote
@nuxt/image and @unlazy/nuxt need to be installed manually. See Peer Dependencies for why.
Register the module in your nuxt.config.ts. Every option is optional.
export default defineNuxtConfig({
modules: ['@maas/magic-image'],
magicImage: {
sizes: '128w:128px 512w:512px 720w:720px 1024w:1024px 1440w:1440px',
image: {
provider: 'maas',
},
unlazy: {
ssr: true,
},
},
})Leave @nuxt/image and @unlazy/nuxt out of modules. Magic Image registers both itself and forwards magicImage.image and magicImage.unlazy to them, so configure them there rather than through their own top-level keys.
Both peer dependencies have to be installed manually. Each one augments your app’s types, and that augmentation only applies where the package resolves from your app itself. Package managers that auto-install peers into their own store, pnpm among them, resolve them somewhere else, and your app stops type checking against their options.
| Package | Version |
|---|---|
| @nuxt/image | ^2.0.0 |
| @unlazy/nuxt | ^2.0.1 |
| Prop | Type | Default | Description |
|---|---|---|---|
src |
string |
– | Image source URL (required) |
provider |
string |
module default | Provider name ('maas', 'mux', or any Nuxt Image provider) |
modifiers |
Partial<MagicImageModifiers> |
– | Provider-specific image transformations |
sizes |
string | Record<string, string | number> |
module default | The width the image is displayed at, per screen |
preset |
string |
– | Nuxt Image preset name |
densities |
string |
– | Device density descriptors (e.g. '1x 2x') |
placeholderSrc |
string |
1×1 GIF | Placeholder shown while loading |
preload |
boolean |
false |
Add <link rel="preload"> to <head> |
autoSizes |
boolean |
true |
Measure the element instead of using the declared sizes |
lazyload |
boolean |
true |
Enable lazy loading |
To customize the module, override the necessary options in your nuxt.config.ts. Any custom options are merged with the defaults.
| Option | Type | Default | Description |
|---|---|---|---|
sizes |
string | Record<string, string | number> |
'128w:128px 512w:512px 720w:720px 1024w:1024px 1440w:1440px' |
Sizes applied to every image, overridden per image by the sizes prop |
image |
Nuxt Image module options | {} |
Passed to Nuxt Image |
unlazy |
Unlazy module options | {} |
Passed to Unlazy |
| Event | Description |
|---|---|
loaded |
Fired when the image has finished loading |
A srcset alone does not decide which candidate the browser downloads. It resolves the candidates against the image’s sizes attribute. Get sizes wrong and the browser picks a candidate that is too small, then upscales it.
autoSizes is on by default, so the element measures itself: sizes is rendered as auto and Unlazy keeps it in line with the element’s layout width. Reach for it whenever the image’s width follows the layout.
Turn autoSizes off to declare the width yourself. The sizes prop is rendered as the sizes attribute, one entry per screen.
<magic-image
src="https://images.unsplash.com/photo-1694444070793-13db645409f4"
sizes="640w:100vw 1024w:50vw"
:auto-sizes="false"
/>The same sizes value also decides which srcset candidates are generated, and the module option applies to every image. So declare a per-image sizes prop whenever an image is displayed at a different width than the module default describes.
Both paths describe the element’s layout width. An image painted with object-fit: cover covers more width than its box whenever the box is taller than the image’s own aspect ratio. Lay such an image out at the size the crop paints, or every candidate is measured against a box narrower than what ends up on screen.
sizes="auto" is only valid on a lazy loaded image. With lazyload off, no sizes attribute is rendered and the browser assumes the image spans the full viewport width.
Built-in provider for the MaaS image CDN. Set provider: 'maas', or use it as the default provider, and pass any of the supported modifiers.
<magic-image
src="https://images.unsplash.com/photo-1694444070793-13db645409f4"
provider="maas"
:modifiers="{
width: 800,
height: 600,
fit: 'cover',
format: 'webp',
quality: 80,
}"
/>| Modifier | Type | Description |
|---|---|---|
width |
number |
Output width in px |
height |
number |
Output height in px |
fit |
'cover' | 'contain' | 'fill' | 'inside' | 'outside' |
Resize fit mode |
format |
'jpg' | 'jpeg' | 'png' | 'webp' |
Output format |
quality |
number |
Output quality (1–100) |
pixelDensity |
number |
Device pixel ratio (e.g. 2 for 2×) |
blur |
number |
Blur radius |
sharpen |
number |
Sharpening strength |
brightness |
number |
Brightness adjustment |
contrast |
number |
Contrast adjustment |
saturation |
number |
Saturation adjustment |
hue |
number |
Hue rotation in degrees |
gamma |
number |
Gamma correction |
filter |
'greyscale' | 'sepia' | 'negative' | 'duotone' |
Color filter |
rotate |
number |
Rotation in degrees |
mirror |
boolean |
Flip horizontally |
mask |
'circle' | 'ellipse' | 'triangle' | 'pentagon' | 'hexagon' | 'square' | 'star' | 'heart' | … |
Shape mask |
background |
string |
Background color |
trimImage |
boolean |
Auto-trim whitespace |
Built-in provider for Mux video thumbnail extraction. Pass the full Mux thumbnail URL as src and set provider="mux".
<magic-image
src="https://image.mux.com/YOUR_PLAYBACK_ID/thumbnail.jpg"
provider="mux"
:modifiers="{
width: 1280,
height: 720,
fit: 'cover',
time: 12,
}"
/>| Modifier | Type | Description |
|---|---|---|
width |
number |
Thumbnail width in px |
height |
number |
Thumbnail height in px |
fit |
'cover' | 'contain' | 'fill' | 'pad' | 'smartcrop' |
Resize fit mode |
time |
number |
Timestamp in seconds to extract thumbnail from |
rotate |
number |
Rotation in degrees |
flipHorizontal |
boolean |
Flip horizontally |
flipVertical |
boolean |
Flip vertically |
start |
number |
Clip start time |
end |
number |
Clip end time |
fps |
number |
Frames per second (for animated thumbnails) |
Import MagicImageModifiers for typed modifier objects.
import type { MagicImageModifiers } from '@maas/magic-image'
const modifiers: Partial<MagicImageModifiers> = {
width: 800,
format: 'webp',
filter: 'greyscale',
}MIT License © 2024-PRESENT Magic as a Service GmbH