Atomic Payload
Plugins

@pro-laico/images

Adds the image and favicon upload collections to your Payload admin: web-ready WebP sizes, a favicon picker field, and an image block for your pages.

@pro-laico/images gives your Payload admin a place to upload images and favicons. The image collection converts uploads to WebP and generates a standard set of responsive sizes, a separate favicons collection keeps favicons out of your main image library, and the package ships a favicon-picker field and an image block you can use elsewhere. It's a tool the atomic-payload template and other plugins bring along, but you can add it on its own too.

@pro-laico/images is a Tool package, a building block of the Atomic Payload stack, meant to be used alongside @pro-laico/core and the other @pro-laico/* packages (most easily via the atomic-payload template), not on its own.

Installation

pnpm add @pro-laico/images
npm install @pro-laico/images
yarn add @pro-laico/images

payload, next, and react are peers you already have in a Payload + Next.js app. @oversightstudio/blur-data-urls is an optional peer. Install it only if you want blur-up placeholders for your images (see Add blur placeholders).

Setup

@pro-laico/core comes bundled with this plugin — it's a dependency, not a separate install. Its cached reads reach Payload through a config you register once in your Next.js instrumentation hook (registerPayloadConfig); see @pro-laico/core → Setup to wire it up.

Adding the image collections to your own Payload project.

Add the plugin to your Payload config

import { buildConfig } from 'payload'
import { imagesPlugin } from '@pro-laico/images'

export default buildConfig({
  plugins: [imagesPlugin({ enabled: true })],
})

This registers the Images collection (where you upload images, and every upload is converted to WebP and given a set of responsive sizes) and the Favicons collection (a separate place for .ico favicons). Both appear under an Assets group in the admin sidebar. Pass includeFavicons: false if you only want the Images collection.

Upload your images

Open the Images collection in the admin and upload your images. Each one gets an alt text field (required, used as the title) and a focal point. Accepted types are PNG, JPEG, WebP, and AVIF.

Add blur placeholders (optional)

The plugin does not wire up blur placeholders itself, because pnpm doesn't install the optional peer next to this package, so the plugin can't reach it. Install @oversightstudio/blur-data-urls yourself and register it after imagesPlugin, passing the exported Images collection:

import { buildConfig } from 'payload'
import { imagesPlugin, Images } from '@pro-laico/images'
import { blurDataUrlsPlugin } from '@oversightstudio/blur-data-urls'

export default buildConfig({
  plugins: [
    imagesPlugin({ enabled: true }),
    blurDataUrlsPlugin({
      enabled: true,
      collections: [Images],
      blurOptions: { blur: 18, width: 32, height: 'auto' },
    }),
  ],
})

That generates a small blurred placeholder for each upload, which the image block can show while the full image loads.

The atomic-payload template already includes @pro-laico/images: the Images and Favicons collections, the blur-placeholder plugin wired against the Images collection, and the image block registered with the other Atomic blocks. You just upload your assets.

Upload images and favicons

Open the Images collection and upload your images (each needs alt text), and the Favicons collection for any .ico favicons.

Pick a favicon

In the Site Metadata global, choose the light and dark favicons for your site. Individual pages can override them in their SEO tab.

Using it in your app

The favicon field

FaviconField is a ready-made upload field that points at the Favicons collection, so you can add a favicon picker to any global or collection. It's what @pro-laico/site uses for the site's favicons; add it to your own config the same way:

import { FaviconField } from '@pro-laico/images'

const SiteMetaData = {
  slug: 'siteMetaData',
  fields: [FaviconField({ name: 'lightFavicon' }), FaviconField({ name: 'darkFavicon' })],
}

Pass a name (and anything else a Payload upload field accepts) to mount more than one picker. The field always targets the favicons collection, so an override can't accidentally re-point it.

The image block

The package ships an Image block (slug ImageChild) that lets editors drop an image into Atomic content. It isn't registered by imagesPlugin. It's one of the default child blocks the Atomic renderer wires up, so in most setups you get it for free. To register it in your own block list, import it from the @pro-laico/images/blocks/imageChild subpath:

import { createImageBlock, Image } from '@pro-laico/images/blocks/imageChild'

// The prebuilt block:
const blocks = [Image]

// …or build your own, prepending/appending fields (e.g. a class-name field):
const customImageBlock = createImageBlock({ prependFields: [], appendFields: [] })

The block lets the editor choose the image, a stored size, alt text, and next/image options (priority, blur, loading, and more). On the front end it renders through @pro-laico/atomic/children, which resolves the chosen image and outputs an optimized next/image.

The Image block is not re-exported from the package root. Import createImageBlock or Image from the @pro-laico/images/blocks/imageChild subpath.

Caching & revalidation

The package ships one cached read, getCachedImage, from the @pro-laico/images/cache subpath. Give it an image document id (and an optional size name) and it returns that upload's URL, reading Payload once instead of on every render. The image block calls it so the block looks up the chosen image by id, which keeps the rest of the page cached even when the image changes.

The Images collection revalidates the matching tag for you: saving an image refreshes its cached URL, and deleting one clears it, so the next page render serves the new URL. See Caching & revalidation for how the tags work.

Options

imagesPlugin(options?) accepts:

Prop

Type

imagesOptions and faviconsOptions are standard Payload Partial<CollectionConfig> objects, so any collection key you pass is merged onto the built-in collection. All options at their defaults, as a working starting point:

imagesPlugin({
  enabled: true,
  includeFavicons: true,
  // imagesOptions and faviconsOptions are unset by default (no overrides merged)
})

Exports

The plugin

Export

Type

imagesPluginplugin
The plugin itself. Registers the Images collection and, with includeFavicons, the Favicons collection. Default and named export.

Parameters

options?:ImagesPluginOptionsSee the Options table above. Everything is optional; omit it to register both collections with their defaults.

Returns

PluginA Payload config plugin you add to buildConfig({ plugins: [...] }).

Example

import { buildConfig } from 'payload'import { imagesPlugin } from '@pro-laico/images'export default buildConfig({plugins: [imagesPlugin({ includeFavicons: true })],})

Location

@pro-laico/images
ImagesPluginOptionstype
The TypeScript type for the plugin's options.

Location

@pro-laico/images

Collections & fields

Export

Type

Imagescollection
The image upload collection (WebP conversion + responsive sizes). Import it to extend the collection or to pass it to the blur-data-URL plugin.

Location

@pro-laico/images
Faviconscollection
The favicon upload collection (.ico), kept separate from the main image library.

Location

@pro-laico/images
FaviconFieldfunction
Builds a reusable favicon-picker upload field that targets the Favicons collection. Drop it into any global or collection. The field always points at the favicons collection, so an override can't re-target it.

Parameters

args?:Partial<UploadField> & { apf?: APFunction[] }Upload-field overrides (name, label, admin, …) merged onto the field; name lets you mount several pickers. apf attaches @pro-laico/core upload hooks via onUploadSetAPF.

Returns

UploadFieldA Payload upload field pointing at the favicons collection.

Example

import type { GlobalConfig } from 'payload'import { FaviconField } from '@pro-laico/images'// a global with light + dark favicon pickersexport const SiteMetaData: GlobalConfig = {slug: 'siteMetaData',fields: [FaviconField({ name: 'lightFavicon' }), FaviconField({ name: 'darkFavicon' })],}

Location

@pro-laico/images

The image block

Export

Type

createImageBlockfunction
Factory for the Image (ImageChild) block. Pass prependFields / appendFields to weave extra fields (e.g. a @pro-laico/styles class-name field) into the start / end of its Image tab.

Parameters

options?:ImageBlockOptions{ prependFields?, appendFields? } arrays of Payload fields spread at the start / end of the Image tab. Omit it to get the block with no extra fields.

Returns

BlockA Payload block (slug ImageChild) you add to a block field or an Atomic child-block list.

Example

import type { Block } from 'payload'import { createImageBlock } from '@pro-laico/images/blocks/imageChild'import { ClassNameField } from '@pro-laico/styles/fields/className'// the Image block with an authored class-name field prependedconst imageBlock: Block = createImageBlock({ prependFields: [ClassNameField({ namePrefix: 'image' })] })

Location

@pro-laico/images/blocks/imageChild
Imageblock
The prebuilt Image block, with no extra fields. What createImageBlock() returns by default.

Location

@pro-laico/images/blocks/imageChild
ImageBlockOptionstype
The TypeScript type for createImageBlock options (prependFields / appendFields).

Location

@pro-laico/images/blocks/imageChild
ImageChildcomponent
The server component that renders the Image block as an optimized next/image. The Atomic children renderer wires it up for the ImageChild slug, so you rarely import it directly.

Parameters

props:RenderChild<ImageChild>The block data and pass-through props the Atomic children renderer supplies (block, pt).

Returns

Promise<JSX.Element>A next/image for the chosen image (resolved through getCachedImage), or a placeholder when no image is set.

Example

import { ImageChild } from '@pro-laico/images/blocks/imageChild/component'// register it for the ImageChild slug in your Atomic children map;// the renderer passes the block + pass-through props for youconst childComponents = {ImageChild,// ...other child block components}

Location

@pro-laico/images/blocks/imageChild/component

Cache getter

Export

Type

getCachedImagefunction
Cached read of an image upload's URL by document id. Returns the named version size if given, else the original. Wrapped in withCache under the image tag and revalidated when the image is saved or deleted, so a page reads it once instead of re-querying Payload on every render. Resolves the config the app registered with registerPayloadConfig.

Parameters

tid:string | null | undefinedThe Images document id (e.g. block.image.id). A falsy id returns an empty string.
version?:string | nullA stored size name (thumbnail, square, small, medium, large, xlarge, og). Omit it for the original upload URL.

Returns

Promise<string | undefined>The image URL, or undefined when the document or size can't be resolved.

Example

import Image from 'next/image'import { getCachedImage } from '@pro-laico/images/cache'// inside the ImageChild server component, the block stores the image as a relationshipexport async function Picture({ block }) {const src = await getCachedImage(block.image?.id, block.version)if (!src) return <div className="w-full h-full bg-gray-200" />return <Image alt={block.alt ?? ''} src={src} />}

Location

@pro-laico/images/cache

Types

Export

Type

Image (type)type
The TypeScript type for an Images document (exported as Image), for typed access to your image data.

Location

@pro-laico/images/schema

On this page