Implementation Patterns

Media & Images

The BreaseImage component wraps Next.js Image with automatic Brease variant support, responsive srcSet generation, and smart fallbacks. This page covers all usage patterns for rendering media from the CMS.


BreaseImage Overview

import { BreaseImage } from 'brease-next'

<BreaseImage breaseImage={media} />

BreaseImage accepts a BreaseMedia object and renders an optimized Next.js Image. It handles variant selection, responsive images, alt text fallbacks, and null safety automatically.

BreaseMedia Type

Media objects returned from the CMS have this structure:

interface BreaseMedia {
  alt: string
  duration: number
  extension: string
  height: number
  mimeGroup: string
  mimeType: string
  name: string
  path: string
  size: string
  thumbnail: string
  uuid: string
  width: number
  variants: Record<string, BreaseMediaVariant>
}

interface BreaseMediaVariant {
  alt: string
  extension: string
  height: number
  mimeType: string
  path: string
  size: string
  type: string
  width: number
}

The variants object contains pre-generated sizes keyed by variant name: sm, md, lg, xl, 2xl, hd, and original.


Responsive Images (Default Behavior)

When no variant prop is provided, BreaseImage automatically builds a srcSet from all available variants, letting the browser pick the best size for the viewport:

import { BreaseImage } from 'brease-next'

// Automatic srcSet from all variants (sm through original)
<BreaseImage breaseImage={elements.heroImage} priority />

The default sizes attribute is:

(max-width: 640px) 100vw, (max-width: 1024px) 50vw, (max-width: 1440px) 33vw, 25vw

This works well for typical content layouts. Override it with the sizes prop for different grid configurations.


Single Variant

Pass a variant prop to use a specific pre-generated size instead of the full srcSet:

// Use the "lg" variant only
<BreaseImage breaseImage={elements.thumbnail} variant="md" />

// Available variants: sm, md, lg, xl, 2xl, hd, original
<BreaseImage breaseImage={elements.banner} variant="xl" />

This is useful for thumbnails, avatars, or fixed-size images where you know exactly which size is appropriate.


Custom Sizes

For grid layouts or other non-default sizing, override the sizes prop:

// Two-column layout
<BreaseImage
  breaseImage={elements.photo}
  sizes="(max-width: 768px) 100vw, 50vw"
  className="rounded-lg"
/>

// Three-column grid
<BreaseImage
  breaseImage={elements.gridImage}
  sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
/>

// Full-width hero
<BreaseImage
  breaseImage={elements.heroImage}
  sizes="100vw"
  priority
/>

Alt Text Fallbacks

BreaseImage uses a fallback chain for alt text:

  1. The alt prop passed directly to the component
  2. breaseImage.alt from the CMS media object
  3. breaseImage.name (the file name)
  4. "Image alt." as a last resort
// Uses alt from CMS media
<BreaseImage breaseImage={media} />

// Override with custom alt text
<BreaseImage breaseImage={media} alt="Custom description" />

Set alt text in the CMS

For best accessibility, set the alt text in the Brease media library. This ensures every usage of the image across your site has meaningful alt text without needing per-component overrides.


Width and Height

BreaseImage infers width and height from the largest available variant, falling back to the original image dimensions (breaseImage.width and breaseImage.height). This prevents layout shift without requiring you to specify dimensions manually.


Priority Loading

For above-the-fold images (heroes, banners), add the priority prop to disable lazy loading and preload the image:

<BreaseImage breaseImage={elements.heroBanner} priority />

Additional Props

BreaseImage passes through standard Next.js Image props like className, style, and priority:

<BreaseImage
  breaseImage={elements.photo}
  variant="lg"
  className="rounded-xl shadow-lg object-cover"
  priority
/>

Configuring Remote Patterns

Next.js requires explicit allowlisting of external image domains. Add the Brease media CDN to your next.config.ts:

// next.config.ts
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'assets.brease.io',
        pathname: '/**',
      },
    ],
  },
}

Image loading errors

If images fail to load with a "hostname not configured" error, check that remotePatterns includes assets.brease.io.


Handling Optional Media Fields

Media fields in sections or collection entries may be null or undefined if the content editor did not upload an image. BreaseImage returns null when breaseImage is falsy, so it is safe to render unconditionally:

// Safe — renders nothing if featuredImage is null
<BreaseImage breaseImage={elements.featuredImage} variant="lg" />

For cases where you want to show a placeholder or conditional wrapper:

{elements.featuredImage ? (
  <BreaseImage
    breaseImage={elements.featuredImage}
    variant="lg"
    className="rounded-lg"
  />
) : (
  <div className="bg-gray-200 rounded-lg aspect-video flex items-center justify-center">
    <span className="text-gray-400">No image</span>
  </div>
)}

Using BreaseMedia Directly with Next.js Image

If you need more control than BreaseImage provides, use the BreaseMedia object with Next.js Image directly:

import Image from 'next/image'
import type { BreaseMedia } from 'brease-next'

interface GalleryProps {
  images: BreaseMedia[]
}

export default function Gallery({ images }: GalleryProps) {
  return (
    <div className="grid grid-cols-3 gap-4">
      {images.map((img) => {
        const variant = img.variants?.lg ?? img.variants?.original
        return (
          <Image
            key={img.uuid}
            src={variant?.path ?? img.path}
            alt={img.alt || img.name || 'Image alt.'}
            width={variant?.width ?? img.width}
            height={variant?.height ?? img.height}
            className="rounded-lg object-cover"
          />
        )
      })}
    </div>
  )
}

Next Steps

Previous
Multi-Locale Sites