brease-next Package

Components

The brease-next package exports five React components for rendering CMS content.

ComponentTypePurpose
BreasePageClientRenders page sections using a component map
BreaseImageClientResponsive image rendering with variant support
BreaseLinkClientSmart internal/external link handling
BreaseStructuredDataServerJSON-LD structured data injection
BreaseCustomCodeServerCustom HTML/script injection

BreasePage

Client component that maps CMS page sections to React components and renders them in order.

Import

import { BreasePage } from 'brease-next'

Props

PropTypeRequiredDescription
pageBreasePageYesThe page object from fetchPage
sectionMapRecord<string, ComponentType<Record<string, unknown>>>YesMaps section keys to React components

How It Works

  1. Iterates through page.sections
  2. For each section, looks up the component from sectionMap using section.key
  3. Spreads section.elements as props to the matched component
  4. Renders with section.uuid as the React key
  5. If no matching component is found for a section key, it is skipped

When rendered inside a BreaseContext, the component automatically uses the page from context if available. This enables live preview mode where the CMS pushes page updates via PostMessage, and BreasePage re-renders with the new content without a page reload.

Usage

// src/lib/brease/brease-config.ts
import { ComponentType } from 'react'
import HeroSection from '@/sections/hero-section'
import FeaturesSection from '@/sections/features-section'
import ContactSection from '@/sections/contact-section'

export const sectionMap: Record<string, ComponentType<Record<string, unknown>>> = {
  hero: HeroSection,
  features: FeaturesSection,
  contact: ContactSection,
}
// src/app/[[...slug]]/page.tsx
import { BreasePage, ensureSuccess } from 'brease-next'
import { sectionMap } from '@/lib/brease/brease-config'
import { getPage } from '@/lib/brease/get-page'
import { notFound } from 'next/navigation'

export default async function Page({ params }: { params: Promise<{ slug?: string[] }> }) {
  const { slug } = await params
  const pageSlug = slug ? slug.join('/') : ''
  const result = await getPage(pageSlug)

  if (!result.success) {
    if (result.status === 404) return notFound()
    throw new Error(result.error)
  }

  return <BreasePage page={result.data} sectionMap={sectionMap} />
}

Section Components

All section components must include 'use client' at the top of the file. BreasePage is a client component and renders sections within a client component tree — server components cannot be used in the section map.

Each section component receives section.elements spread as props. Type your props based on the elements you configured in the CMS:

'use client'

import { BreaseMedia, BreaseLinkData } from 'brease-next'

interface HeroSectionProps {
  title: string
  subtitle: string
  heroImage: BreaseMedia
  ctaButton: BreaseLinkData
}

export default function HeroSection({ title, subtitle, heroImage, ctaButton }: HeroSectionProps) {
  return (
    <section>
      <h1>{title}</h1>
      {subtitle && <p>{subtitle}</p>}
    </section>
  )
}

BreaseImage

Wraps the Next.js Image component with Brease media data. Supports responsive variant-based srcSet and named variant selection.

Import

import { BreaseImage } from 'brease-next'

Props

PropTypeRequiredDescription
breaseImageBreaseMediaYesThe media object from CMS elements
variant'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'hd' | 'original'NoRender a specific variant instead of responsive srcSet
altstringNoOverride the alt text from the media object
sizesstringNoThe sizes attribute for responsive images
...restany Next.js Image propsNoAll other props are passed to the underlying Image component

Variant Behavior

When no variant is specified, the component generates a responsive srcSet from all available variants. The variants are ordered by size: sm, md, lg, xl, 2xl, hd, original.

When a specific variant is provided, only that variant is rendered.

Usage

Responsive (automatic srcSet):

import { BreaseImage, type BreaseMedia } from 'brease-next'

interface HeroProps {
  heroImage: BreaseMedia
}

export default function HeroSection({ heroImage }: HeroProps) {
  return (
    <BreaseImage
      breaseImage={heroImage}
      sizes="100vw"
      className="w-full h-auto"
      priority
    />
  )
}

Specific variant:

<BreaseImage
  breaseImage={thumbnail}
  variant="sm"
  className="rounded-full w-12 h-12"
/>

With alt text override:

<BreaseImage
  breaseImage={productImage}
  alt="Product hero shot"
  sizes="(max-width: 768px) 100vw, 50vw"
/>

Null Handling

Returns null if breaseImage is falsy, so you can safely pass optional media elements without conditional rendering.


Smart link component that renders internal links with Next.js Link and external links with a native <a> tag.

Import

import { BreaseLink } from 'brease-next'

Props

PropTypeRequiredDescription
linkDataBreaseLinkDataYesLink data object from CMS elements
childrenReactNodeYesLink content
...restanchor/Link propsNoAdditional props passed to the underlying element
interface BreaseLinkData {
  label: string       // Display label (you can use children instead)
  isExternal: boolean // Whether the link points to an external URL
  value: string       // The URL or path
  target: '_blank' | '_self' | null
}

Behavior

  • Internal links (isExternal: false): rendered with Next.js <Link> for client-side navigation
  • External links (isExternal: true): rendered with a native <a> tag
  • When target is '_blank', rel="noopener noreferrer" is automatically added for security

Usage

import { BreaseLink, type BreaseLinkData } from 'brease-next'

interface CtaSectionProps {
  heading: string
  ctaLink: BreaseLinkData
}

export default function CtaSection({ heading, ctaLink }: CtaSectionProps) {
  return (
    <section>
      <h2>{heading}</h2>
      <BreaseLink linkData={ctaLink} className="btn btn-primary">
        {ctaLink.label}
      </BreaseLink>
    </section>
  )
}

With custom children:

<BreaseLink linkData={link}>
  <span className="icon">-></span>
  <span>Read more</span>
</BreaseLink>

BreaseStructuredData

Server component that renders JSON-LD structured data from page.structuredData as a <script type="application/ld+json"> tag.

Import

import { BreaseStructuredData } from 'brease-next'

Props

PropTypeRequiredDescription
pageBreasePageYesThe page object containing structuredData

Behavior

  • Reads page.structuredData (an array of JSON-LD objects)
  • Renders each as a <script type="application/ld+json"> tag
  • Renders nothing if page.structuredData is null or empty

Usage

import { BreaseStructuredData, ensureSuccess, fetchPage } from 'brease-next'

export default async function Page() {
  const page = ensureSuccess(await fetchPage('about-us'))

  return (
    <>
      <BreaseStructuredData page={page} />
      {/* rest of page */}
    </>
  )
}

Structured data is managed in the CMS page settings. Common schemas include Organization, Article, Product, FAQ, and BreadcrumbList.


BreaseCustomCode

Server component that renders custom HTML and scripts from page.customCode. Useful for analytics snippets, third-party widgets, or page-specific scripts managed in the CMS.

Import

import { BreaseCustomCode } from 'brease-next'

Props

PropTypeRequiredDescription
pageBreasePageYesThe page object containing customCode

Behavior

  • Reads page.customCode (a string of HTML/script content)
  • Renders the content using dangerouslySetInnerHTML
  • Renders nothing if page.customCode is null or empty

Usage

import { BreaseCustomCode, ensureSuccess, fetchPage } from 'brease-next'

export default async function Page() {
  const page = ensureSuccess(await fetchPage('about-us'))

  return (
    <>
      {/* page content */}
      <BreaseCustomCode page={page} />
    </>
  )
}

Custom code is managed per page in the CMS page settings. Site-wide custom code is available via BreaseSite.customCode.


Next Steps

Previous
API Reference