Docs
Next

Feature

Put full-height media and a content column side by side in one band, mirrored or themed, stacking on phones.

On this page

Feature is a full-width band with media on one half and content on the other. The media runs edge to edge on its side, and the content column lines up with the page container on the other. Below the md breakpoint the two stack, media first.

import {
  Button,
  Feature,
  FeatureContent,
  FeatureMedia,
  Heading,
  Image,
  Paragraph,
} from '@systhemaui/next'

export default function Demo() {
  return (
    <Feature layoutBackground="alternative">
      <FeatureMedia>
        <Image
          src="/demo-assets/workspace.webp"
          alt="A desk with a laptop and design sketches"
          width={1800}
          height={1200}
        />
      </FeatureMedia>
      <FeatureContent>
        <Paragraph type="label">Studio</Paragraph>
        <Heading.h2>Built around how you work</Heading.h2>
        <Paragraph>
          The media fills its half of the band at any height, and the content column aligns with the
          page container on the other side.
        </Paragraph>
        <Paragraph>
          <Button.a href="#" variant="primary">
            Meet the team
          </Button.a>
        </Paragraph>
      </FeatureContent>
    </Feature>
  )
}

ImportLink to this section

import { Feature, FeatureContent, FeatureMedia } from '@systhemaui/next'

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

Parts and tagsLink to this section

  • Feature: the <section class="feature"> band. It takes theme, layoutBackground and reversed.
  • FeatureMedia: the media half, at least --feature-media-min-height tall (320px when the token is unset). Put an Image, Video or MediaWrapper inside it, or render the media element itself with a tag variant: FeatureMedia.img, FeatureMedia.video, FeatureMedia.iframe or FeatureMedia.div. as takes any other element.
  • FeatureContent: the content half, a rich-text box (feature-content richtext). FeatureContent.div and as change its element.

Media inside FeatureMedia loses its border radius and shadow and is cropped with object-fit: cover, so it reads as part of the band.

ExamplesLink to this section

ReversedLink to this section

reversed puts the media on the right from md up. On a phone the media stays on top.

import { Feature, FeatureContent, FeatureMedia, Heading, Image, Paragraph } from '@systhemaui/next'

export default function Demo() {
  return (
    <Feature reversed>
      <FeatureMedia>
        <Image
          src="/demo-assets/forest-portrait.webp"
          alt="Sunlight through a pine forest"
          width={1200}
          height={1600}
        />
      </FeatureMedia>
      <FeatureContent>
        <Heading.h2>Media on the right</Heading.h2>
        <Paragraph>
          Alternate reversed and regular features down a page to give a long story some rhythm.
        </Paragraph>
      </FeatureContent>
    </Feature>
  )
}

ThemeLink to this section

theme switches the band to another color-system mode, and layoutBackground picks the main or alternative background of that mode.

import { Feature, FeatureContent, FeatureMedia, Heading, Paragraph } from '@systhemaui/next'

export default function Demo() {
  return (
    <Feature theme="dark" layoutBackground="main">
      <FeatureMedia.img src="/demo-assets/city.webp" alt="A city skyline at night" />
      <FeatureContent>
        <Heading.h2>After dark</Heading.h2>
        <Paragraph>
          theme="dark" sets data-theme on the band. Here the media is rendered as the img element
          itself with FeatureMedia.img.
        </Paragraph>
      </FeatureContent>
    </Feature>
  )
}

Features in a rowLink to this section

Consecutive features inside an Article sit edge to edge: a feature is a <section>, and the article puts one section padding above and below a run of sections and none between them.

Alternating features
import {
  Article,
  Feature,
  FeatureContent,
  FeatureMedia,
  Heading,
  Image,
  Paragraph,
} from '@systhemaui/next'

export default function Demo() {
  return (
    <Article>
      <Feature>
        <FeatureMedia>
          <Image src="/demo-assets/dunes-portrait.webp" alt="Sand dunes" width={1200} height={1600} />
        </FeatureMedia>
        <FeatureContent>
          <Heading.h3>Research</Heading.h3>
          <Paragraph>We start with the people who will use the site.</Paragraph>
        </FeatureContent>
      </Feature>
      <Feature reversed layoutBackground="alternative">
        <FeatureMedia>
          <Image
            src="/demo-assets/abstract-square.webp"
            alt="Abstract colored shapes"
            width={1200}
            height={1200}
          />
        </FeatureMedia>
        <FeatureContent>
          <Heading.h3>Design</Heading.h3>
          <Paragraph>Then we turn what we learned into a design system.</Paragraph>
        </FeatureContent>
      </Feature>
    </Article>
  )
}

PropsLink to this section

FeatureLink to this section

All other props go to the <section> element.

PropTypeDefaultDescription
themeColorSystem (dark, default)-
layoutBackgroundLayoutBackground (main, alternative)-
reversedbooleanfalse
…and all <section> attributes

FeatureMediaLink to this section

PropTypeDefaultDescription
asElementType'div'
classNamestring-
…and all <div> attributes

FeatureContentLink to this section

PropTypeDefaultDescription
asElementType'div'
classNamestring-
…and all <div> attributes

HTML and CSSLink to this section

The same band in plain HTML:

<section class="feature feature-reversed bg-layout-alternative" data-theme="dark">
  <img class="feature-media" src="/images/studio.webp" alt="Our studio" />
  <div class="feature-content richtext">
    <h2 class="color-heading text-h2">Built around how you work</h2>
    <p class="text-body color-body">Media on one half, content on the other.</p>
  </div>
</section>

The content padding comes from the --feature-content-padding-side, --feature-content-padding-center and --feature-content-padding-y tokens, and the media height from --feature-media-min-height:

ClassStyles
feature& { width: 100%; display: flex; flex-direction: row; justify-content: flex-start; }@media (width < 640px) { & { flex-direction: column; } }@media (width >= 640px) { &.feature-reversed { flex-direction: row-reverse; } }@media (width >= 640px) { &.feature-reversed .feature-content { margin-right: 0; margin-left: var(--container-margin); padding-left: var(--feature-content-padding-side); padding-right: var(--feature-content-padding-center); } }
feature-media& { flex-grow: 0; flex-shrink: 0; display: flex; width: 100%; min-height: var(--feature-media-min-height, 320px); }@media (width >= 640px) { & { width: 50%; } }&:is(img, svg, video, iframe, .media, .media-wrapper), .feature-media > *:is(img, svg, video, iframe, .media, .media-wrapper) { height: unset; object-fit: cover; object-position: center; border-radius: 0; box-shadow: none; }
feature-content& { width: 100%; padding-left: var(--feature-content-padding-center); padding-right: var(--feature-content-padding-side); padding-block: var(--feature-content-padding-y, 48px); align-self: stretch; }@media (max-width: 639px) { & { width: calc(100% - var(--container-margin) * 2); max-width: var(--container-width); margin-inline: auto; } }@media (width >= 640px) { & { width: calc(var(--container-width) / 2); margin-right: var(--container-margin); align-self: center; } }
feature-reversed@media (width >= 640px) { .feature.feature-reversed { flex-direction: row-reverse; } }@media (width >= 640px) { .feature.feature-reversed .feature-content { margin-right: 0; margin-left: var(--container-margin); padding-left: var(--feature-content-padding-side); padding-right: var(--feature-content-padding-center); } }

Next.jsLink to this section

@systhemaui/next re-exports Feature, FeatureMedia and FeatureContent from @systhemaui/react unchanged. Put the @systhemaui/next Image inside FeatureMedia to get next/image optimization; the tag variant FeatureMedia.img renders a plain <img>.

AccessibilityLink to this section

The media comes first in the source and the content second, whichever side reversed shows them on, so screen readers always read media then text. Give informative images an alt; pass alt="" when the image only decorates the band.