Docs

This page isn't translated yet

Figure

Wrap images and media in a figure that keeps to the text column or breaks out to container, screen or card width.

On this page

Figure wraps an image, video or embed in a <figure> and controls how wide it gets. By default it follows the column it sits in; width lets it break out of a narrow column to the container, the whole viewport, or the inner edges of a card.

import { Figure, Heading, Image, Paragraph, Section } from '@systhemaui/next'

export default function Demo() {
  return (
    <Section padding={3}>
      <Heading.h2>Ten days on the coast</Heading.h2>
      <Paragraph>
        A figure placed in a section's text column breaks out to the container width, while the text
        around it keeps its comfortable measure.
      </Paragraph>
      <Figure width="container">
        <Image
          src="/demo-assets/coast.webp"
          alt="Waves breaking on a rocky coast"
          width={1800}
          height={1200}
          aspectRatio="21/9"
        />
        <figcaption className="text-small color-label">The northern cliffs at low tide.</figcaption>
      </Figure>
      <Paragraph>The text continues in its column after the figure.</Paragraph>
    </Section>
  )
}

ImportLink to this section

import { Figure } from '@systhemaui/next'

In a React app without Next.js, import it from @systhemaui/react.

Width and breakout behaviourLink to this section

widthClassResult
defaultfigure-w-defaultFills the column it sits in. No breakout rule.
containerfigure-w-containerBreaks out of any narrower ancestor to --container-width (or the viewport, when narrower).
screenfigure-w-screenBreaks out to the full viewport width and never animates in on scroll.
cardfigure-w-cardBreaks out to the inner edges of the surrounding card. Outside a card it has no effect.

The breakouts use negative margins (calc(50% - 50vw) for screen), so the figure's grid cell keeps its place and the content before and after it stays aligned.

ExamplesLink to this section

Default, container and screenLink to this section

The three widths inside a section with padding={3}. Switch the preview to the phone viewport: below md the column has no inset, so default and container look the same there.

import { Figure, Image, Paragraph, Section } from '@systhemaui/next'

export default function Demo() {
  return (
    <Section padding={3}>
      <Paragraph type="label">width="default"</Paragraph>
      <Figure>
        <Image src="/demo-assets/city.webp" alt="" width={1920} height={1080} aspectRatio="21/9" />
      </Figure>
      <Paragraph type="label">width="container"</Paragraph>
      <Figure width="container">
        <Image
          src="/demo-assets/mountains.webp"
          alt=""
          width={1920}
          height={1080}
          aspectRatio="21/9"
        />
      </Figure>
      <Paragraph type="label">width="screen"</Paragraph>
      <Figure width="screen">
        <Image src="/demo-assets/coast.webp" alt="" width={1800} height={1200} aspectRatio="21/9" />
      </Figure>
    </Section>
  )
}

A screen figure that is the first or last child of a Section or an Article removes that container's padding on its side, so it sits flush against the edge. container figures keep the padding.

Card widthLink to this section

width="card" cancels the card's horizontal padding through the --card-width-offset-x variable every card publishes. As the first or last child, the card also drops its own top or bottom padding, so the image meets the card's rounded edge while the text keeps its padding.

Card-width figure
import { Card, Column, Columns, Figure, Heading, Image, Paragraph } from '@systhemaui/next'

export default function Demo() {
  return (
    <Columns columns={2} gap="md" className="w-full max-w-3xl">
      <Column>
        <Card variant="default">
          <Figure width="card">
            <Image
              src="/demo-assets/dunes-portrait.webp"
              alt=""
              width={1200}
              height={1600}
              aspectRatio="16/10"
            />
          </Figure>
          <Heading.h4>Desert crossing</Heading.h4>
          <Paragraph>The image bleeds to the card's edges.</Paragraph>
        </Card>
      </Column>
      <Column>
        <Card variant="default">
          <Figure>
            <Image
              src="/demo-assets/forest-portrait.webp"
              alt=""
              width={1200}
              height={1600}
              aspectRatio="16/10"
            />
          </Figure>
          <Heading.h4>Forest trail</Heading.h4>
          <Paragraph>The default width keeps the card's padding.</Paragraph>
        </Card>
      </Column>
    </Columns>
  )
}

The figure-rendering Payload media blocks (image, video, YouTube, Google Maps and embed) offer the same card width when they sit directly inside a card. See Media inside a card.

CaptionsLink to this section

Put a <figcaption> after the media. Figure adds no caption styling, so style it with a text utility such as text-small.

PropsLink to this section

width defaults to 'default'. All other props go to the <figure> element, including dangerouslySetInnerHTML, which renders the figure without children (the embed block converter uses it).

PropTypeDefaultDescription
childrenReactNode-
width'default' | 'container' | 'screen' | 'card' | null-
classNamestring-
…and all <figure> attributes

HTML and CSSLink to this section

The same figure in plain HTML:

<figure class="figure-w-container">
  <img class="media aspect-21/9 object-cover" src="/images/coast.webp" alt="A rocky coast" />
  <figcaption class="text-small">The northern cliffs at low tide.</figcaption>
</figure>

w-card is an exact alias of figure-w-card for any element. figure-w-full is a deprecated alias of figure-w-screen, kept for older content; systhema upgrade rewrites it in your source. See Figure width.

ClassStyles
figure-w-containerwidth: min(var(--container-width), 100vw);max-width: 100vw;margin-left: calc((100% - min(var(--container-width), 100vw)) / 2);margin-right: calc((100% - min(var(--container-width), 100vw)) / 2);margin-block: 0;
figure-w-screen.py-section:where(:has( > .container > .richtext > .figure-w-screen:first-child, > .container > .richtext > .figure-w-full:first-child, > .container > .figure-w-screen:first-child, > .container > .figure-w-full:first-child)) { padding-top: 0; }+ 2 more rules
figure-w-full.py-section:where(:has( > .container > .richtext > .figure-w-screen:first-child, > .container > .richtext > .figure-w-full:first-child, > .container > .figure-w-screen:first-child, > .container > .figure-w-full:first-child)) { padding-top: 0; }+ 2 more rules
figure-w-card& { width: calc(100% + var(--card-width-offset-x, 0px) * 2); max-width: calc(100% + var(--card-width-offset-x, 0px) * 2); margin-inline: calc(var(--card-width-offset-x, 0px) * -1); border-radius: 0; }& :is(.media, .media-wrapper) { border-radius: 0; }
w-card& { width: calc(100% + var(--card-width-offset-x, 0px) * 2); max-width: calc(100% + var(--card-width-offset-x, 0px) * 2); margin-inline: calc(var(--card-width-offset-x, 0px) * -1); border-radius: 0; }& :is(.media, .media-wrapper) { border-radius: 0; }

Next.jsLink to this section

@systhemaui/next re-exports Figure from @systhemaui/react unchanged. Put the @systhemaui/next Image or Video inside it.

AccessibilityLink to this section

A <figcaption> names the figure for assistive technology, so it can describe the image while alt stays short, or the image can take alt="" when the caption already says everything. Don't repeat the same text in both.