Images

Developer preview

This feature is in developer preview. Use with caution as it may change unexpectedly. For more information, contact us.

Goal: show an image that an author selects in an asset parameter. Use the next/image component, so that Next.js optimizes the image.

  • A Next.js app with the SDK. Refer to Next.js App Router SDK.

  • A component definition with a parameter of the type Asset, for example image.

  • The @uniformdev/canvas package, at the same version as the SDK:

    v=20.81.1-alpha.25.sha-f076f9b857 npm install @uniformdev/canvas@$v

The type of an asset parameter value is AssetParamValue from @uniformdev/canvas. It is an array of asset items, because an asset parameter can have more than one asset. Each item keeps its data in fields, and each field has a type and a value:

[ { "type": "image", "_id": "69197033-6dcb-49f2-91bf-a3c8246ff8ee", "_source": "uniform-assets", "fields": { "url": { "type": "text", "value": "https://img.uniform.global/p/…/some-image.png" }, "title": { "type": "text", "value": "Asset Title" }, "description": { "type": "text", "value": "This is an image showing something interesting" }, "width": { "type": "number", "value": 1000 }, "height": { "type": "number", "value": 563 } } } ]

flattenValues from @uniformdev/canvas changes each item into an object with plain values: url, id, title, description, mediaType, width, height, size, focalPoint and custom. Only url is always in the data. The other fields can be undefined.

CallResult
flattenValues(image?.value)An array of flat assets
flattenValues(image?.value, { toSingle: true })The first flat asset, or undefined for an empty array

Give flattenValues the parameter value (image?.value), not the parameter object (image). The function reads the fields of each item.

next/image loads remote images only from the hosts in images.remotePatterns. The Uniform asset library delivers images from img.uniform.global (US) and img.eu.uniform.global (EU):

next.config.ts

import { withUniformConfig } from "@uniformdev/next-app-router/config"; import type { NextConfig } from "next"; const nextConfig: NextConfig = { images: { remotePatterns: [ { protocol: "https", hostname: "img.uniform.global" }, { protocol: "https", hostname: "img.eu.uniform.global" }, ], }, }; export default withUniformConfig(nextConfig);

note

An asset can also come from a DAM integration or from a custom URL. Its url then has a different host. Add each of these hosts to remotePatterns. Without the host, next/image gives an error for the image.

components/feature-image.tsx

import { type AssetParamValue, flattenValues } from "@uniformdev/canvas"; import type { ComponentParameter, ComponentProps } from "@uniformdev/next-app-router/component"; import Image from "next/image"; type FeatureImageParameters = { image?: ComponentParameter<AssetParamValue>; }; export const FeatureImage = ({ parameters: { image }, context, }: ComponentProps<FeatureImageParameters>) => { // The first asset of the parameter, with plain values: url, title, width, height and more. const asset = flattenValues(image?.value, { toSingle: true }); // No image: show a placeholder in Canvas, and nothing on the live site. if (!asset?.url) { return context.isContextualEditing ? ( <div className="flex aspect-video items-center justify-center bg-gray-100">Select an image</div> ) : null; } const alt = asset.description ?? asset.title ?? ""; // The asset has its size: give it to next/image. if (asset.width && asset.height) { return ( <Image src={asset.url} alt={alt} width={asset.width} height={asset.height} sizes="(max-width: 768px) 100vw, 50vw" className="h-auto w-full" /> ); } // The asset has no size: fill a box that has a fixed aspect ratio. return ( <div className="relative aspect-video"> <Image src={asset.url} alt={alt} fill sizes="(max-width: 768px) 100vw, 50vw" className="object-cover" /> </div> ); };

Register the component in components/resolveComponent.tsx. Refer to Next.js App Router SDK.

Without toSingle, flattenValues returns all assets of the parameter:

components/gallery.tsx

import { type AssetParamValue, flattenValues } from "@uniformdev/canvas"; import type { ComponentParameter, ComponentProps } from "@uniformdev/next-app-router/component"; import Image from "next/image"; type GalleryParameters = { images?: ComponentParameter<AssetParamValue>; }; export const Gallery = ({ parameters: { images } }: ComponentProps<GalleryParameters>) => { const assets = flattenValues(images?.value) ?? []; return ( <div className="grid grid-cols-3 gap-4"> {assets.map((asset, index) => asset.url && asset.width && asset.height ? ( <Image key={index} src={asset.url} alt={asset.description ?? asset.title ?? ""} width={asset.width} height={asset.height} sizes="33vw" /> ) : null )} </div> ); };
  • Alt text: an asset has no alt field. The example uses the description of the asset, then its title. To set a different text in each component, add a text parameter for the alt text. For an image that is only decoration, use alt="".
  • Width and height: next/image must have width and height, or fill. For an image, Uniform gives the size of the original image in width and height. Other assets, and assets from a custom URL or a DAM integration, can have no size. Then the example uses fill in a box with a fixed aspect ratio.
  • Fallback: an author can add a component and not select an image. Then flattenValues returns undefined. In Canvas, context.isContextualEditing is true, so the example shows a placeholder that tells the author to select an image. On the live site, it renders nothing.
  • The main image of a page: for the largest image at the top of a page, add preload to Image. Next.js 16 replaced the priority property with preload.
  • Image transformations: the Uniform image delivery API can crop and resize images with query parameters. imageFrom from @uniformdev/assets makes these URLs. Refer to Image Delivery API.