Skip to content

Patterns · Layout

Marketing sections

MarketingSection, MarketingSectionHeader, FeatureGrid, ProductFrame, StatStrip, CTABand and FAQ: the body of a public page.

@rookcom/monarch-react/marketingPattern

Section with features

The editor

Every idea gets the right shape.

Type a slash and pick a block.

  • Slash commands

    Tables, lists and callouts, one keystroke away.

  • Version history

    Named snapshots you can restore safely.

Usage examples

Product frame, stats, FAQ and CTA

Purpose

The building blocks between hero and footer. Each is a small, opinionated pattern so product sites share rhythm, type and colour without local CSS. Import from @rookcom/monarch-react/marketing.

Use when

  • MarketingSection for every band after the hero; MarketingSectionHeader at its top.
  • FeatureGrid for capabilities or benefits; ProductFrame for product illustrations.
  • StatStrip for a few true figures; FAQ for buyer questions; CTABand once, at the end.

Avoid when

  • Signed-in app screens: use Card, StatCard, SettingsSection and the app layouts.
  • In-app section headings: use the planned section-header.

Design principles

  • Rhythm from tokens: sections pad with --mn-section-{sm,md,lg}, content sits in --mn-width-{narrow,content,wide}.
  • One accent: eyebrows, feature icons and the CTA band use the product accent; gradients are derived from it, never hand-picked.
  • tone="inverse" is the only dark band. Inside it Monarch remaps text, borders, surfaces, accent text and focus ring, all contrast-tested for every product. In dark themes it becomes an elevated surface instead of flipping to light.
  • Illustrations are presentational: ProductFrame is one labelled image whose contents are inert.

API reference

import { CTABand, FAQ, FeatureGrid, MarketingSection, MarketingSectionHeader, ProductFrame, StatStrip } from '@rookcom/monarch-react/marketing';
ExportKindRenderingRoot class
CTABandcomponentserver-safe.mn-cta
FAQcomponentclient.mn-faq
FeatureGridcomponentserver-safe.mn-feature-grid
MarketingSectioncomponentserver-safe.mn-msection
MarketingSectionHeadercomponentserver-safe.mn-msection
ProductFramecomponentserver-safe.mn-product-frame
StatStripcomponentserver-safe.mn-stat-strip

FeatureGrid renders a <ul>; items with href become one stretched link per card.

StatStrip renders a <dl>: label (dt) first for screen readers, value shown first visually.

FAQ wraps Accordion (type="single" collapsible unless multiple).

CTABand on tone="accent" inverts primary and secondary Buttons inside it.

Generated from the TypeScript declarations of packages/react/src/patterns/layout/marketing-section-blocks.

Properties

CTABand

A closing call to action. Server-component safe.

PropTypeDescription
title requiredReactNode
actionsReactNodeButtons. On the `accent` tone, Monarch inverts Button colours automatically.
childrenReactNode
classNamestring
descriptionReactNode
headingAsHeadingLevel
idstring
tone"accent" | "subtle" | "inverse"`accent` for the closing call to action; `subtle` and `inverse` for quieter moments.

FAQ

Frequently asked questions. Answer the question a buyer actually has; never internal notes. Each question is a heading, so the list appears in the outline.

PropTypeDescription
items requiredFAQItem[]
classNamestring
defaultOpennumberIndex of the question open on first render.
headingAsHeadingLevelHeading element for each question.
multiplebooleanAllow several answers open at once. Default false.

FeatureGrid

Grid of features or benefits. Linked cards use one stretched link per card, so each is a single tab stop with the title as its name. Server-component safe.

PropTypeDescription
items requiredFeatureItem[]
childrenReactNode
classNamestring
columns3 | 4 | 2
headingAsHeadingLevelHeading element for each item title.
idstring
variant"card" | "plain"`card` adds a bordered surface; `plain` is for dense lists.

MarketingSection

A full-width band with a centred content column. Server-component safe.

PropTypeDescription
childrenReactNode
classNamestring
idstring
spacing"sm" | "md" | "lg"Vertical padding from the section rhythm scale.
tone"default" | "subtle" | "inverse"`default` on the page canvas, `subtle` for a quiet alternate band, `inverse` for one high-emphasis band. Inside `inverse`, Monarch remaps text, borders, surfaces, accent text and focus ring, so nested components stay readable.
width"content" | "wide" | "narrow"Content width.

MarketingSectionHeader

Eyebrow, display title and description at the top of a marketing section. (In-app section headings are the planned `section-header`.) Server-component safe.

PropTypeDescription
title requiredReactNode
actionsReactNodeOptional link or button beside a start-aligned header.
align"center" | "start"
childrenReactNode
classNamestring
descriptionReactNode
eyebrowReactNode
headingAsHeadingLevelHeading element; `h2` for page sections.
idstring
size"md" | "lg"Title size from the display scale.
titleIdstringId for the title, so the section can use `aria-labelledby`.

ProductFrame

Neutral frame for product illustrations. The contents are presentational: one `role="img"` with `label`, and `inert`, so sample headings and inputs are neither read out nor focusable. Server-component safe.

PropTypeDescription
children requiredReactNodeThe illustrated UI. Build it from Monarch components so it stays on-brand.
label requiredstringAccessible description of the illustration, e.g. "Dossier editor with an outline and the Assistant panel". Required: the frame is announced as one image.
backdropbooleanA soft accent panel behind the frame, for hero moments.
captionReactNodeVisible caption under the frame.
chrome"none" | "window" | "browser"`window` (app window dots), `browser` (address bar) or `none`.
classNamestring
idstring
titlestringText in the chrome bar: a document title, or a URL with `chrome="browser"`.

StatStrip

A row of key figures as a description list. Server-component safe.

PropTypeDescription
items requiredStatItem[]
childrenReactNode
classNamestring
idstring

Variants

PropValuesDescription
tone (MarketingSection)'default''subtle''inverse'Canvas, quiet alternate band, or the one high-emphasis band.
spacing (MarketingSection)'sm''md''lg'Vertical padding from the section rhythm scale.
width (MarketingSection)'narrow''content''wide'44rem, 72rem or 80rem content column.
align / size (MarketingSectionHeader)'start | center''md | lg'Alignment and display size of the title.
columns / variant (FeatureGrid)'2 | 3 | 4''card | plain'Columns at full width; bordered cards or a plain list.
chrome / backdrop (ProductFrame)'window | browser | none''true | false'App-window dots, a URL bar or nothing; optional soft accent panel behind.
tone (CTABand)'accent''subtle''inverse'Accent gradient (default), quiet panel, or dark panel.

States

StateExposed asBehaviour
Linked feature hoverdata-linkedBorder strengthens and a medium shadow appears.
FAQ item opendata-state="open"From Accordion.

Interaction behaviour

  • Only linked FeatureGrid cards, FAQ questions and the actions you pass are interactive.
  • ProductFrame contents never receive focus or pointer events (inert).

Keyboard support

KeysAction
TabLinked feature cards are one tab stop each; FAQ triggers follow.
Enter / SpaceOpens a linked card or toggles a FAQ answer.
Arrow Up / Down, Home / EndMove between FAQ questions.

Accessibility

  • Label each MarketingSection with aria-labelledby pointing at its header titleId, so it becomes a named region.
  • Headings come from props (headingAs) so the outline never skips: h2 for sections, h3 for features and questions.
  • ProductFrame requires label; contents are inert so sample headings and inputs stay out of the outline and tab order.
  • Feature icons are decorative (aria-hidden).
  • Inverse sections keep 4.5:1 text contrast (7:1 more-contrast) for every Rook product, including accent text on cards within the band.

Responsive behaviour

  • FeatureGrid: one column, two from 640px, three or four from 1024px.
  • StatStrip: two columns, three or four from 1024px, with hairline separators that follow the grid.
  • CTABand: stacked copy and actions; side by side from 1024px.

Theme support

  • Subtle bands use --mn-color-bg-subtle; inverse bands --mn-gradient-inverse; CTA --mn-gradient-accent; all follow the product accent.
  • Verified in light, dark and more-contrast with the default, Dossier, Calendar and Base accents (visual baselines).

Do and don't

Do

  • Alternate default and subtle bands; use inverse at most once per page.
  • Build ProductFrame contents from Monarch components so illustrations stay on-brand.
  • Use only true, current numbers in StatStrip.

Don't

  • Do not hand-pick colours or gradients (hex values, arbitrary colour classes, near-black section fills); use the tones.
  • Do not use two CTA bands or more than one primary action per section.
  • Do not use sparkle icons for AI features; use a plain Bot icon.
  • Do not write FAQ entries that are internal notes ("Is this implemented?").

Dependencies

KindDepends on
npm packagesNone
Monarch componentsAccordion

Tokens: --mn-display-*, --mn-section-*, --mn-width-*, --mn-gradient-{wash,accent,inverse}, --mn-color-*-inverse*, --mn-color-accent-strong-inverse.

Testing coverage

  • All blocks compose with no axe violations and render on the server.
  • MarketingSection sets tone, spacing and width and is named by its h2.
  • ProductFrame is one labelled image with inert contents.
  • Linked FeatureGrid cards are one tab stop named by the title.
  • StatStrip pairs dt labels with dd values.
  • FAQ honours defaultOpen and toggles from the keyboard.
  • CTABand heading level and tone.
CheckCovered
Axe in jsdomYes
Server renderingYes
Browser suitesVisual baselines: /__marketing in light, dark and more-contrast × 4 accents × 1280/390; Three-browser axe: /__marketing

Tests: packages/react/src/patterns/layout/marketing-section-blocks