Source: https://monarchui.dev/components/marketing-section-blocks/

Patterns · Layout

# Marketing sections

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

@rookcom/monarch-react/marketing

Pattern

## Section with features

## 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

```tsx
import { CTABand, FAQ, FeatureGrid, MarketingSection, MarketingSectionHeader, ProductFrame, StatStrip } from '@rookcom/monarch-react/marketing';
```

| Export | Kind | Rendering | Root class |
| --- | --- | --- | --- |
| `CTABand` | component | server-safe | `.mn-cta` |
| `FAQ` | component | client | `.mn-faq` |
| `FeatureGrid` | component | server-safe | `.mn-feature-grid` |
| `MarketingSection` | component | server-safe | `.mn-msection` |
| `MarketingSectionHeader` | component | server-safe | `.mn-msection` |
| `ProductFrame` | component | server-safe | `.mn-product-frame` |
| `StatStrip` | component | server-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.

| Prop | Type | Description |
| --- | --- | --- |
| `title` required | `ReactNode` |  |
| `actions` | `ReactNode` | Buttons. On the `accent` tone, Monarch inverts Button colours automatically. |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `description` | `ReactNode` |  |
| `headingAs` | `HeadingLevel` |  |
| `id` | `string` |  |
| `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.

| Prop | Type | Description |
| --- | --- | --- |
| `items` required | `FAQItem[]` |  |
| `className` | `string` |  |
| `defaultOpen` | `number` | Index of the question open on first render. |
| `headingAs` | `HeadingLevel` | Heading element for each question. |
| `multiple` | `boolean` | Allow 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.

| Prop | Type | Description |
| --- | --- | --- |
| `items` required | `FeatureItem[]` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `columns` | `3 \| 4 \| 2` |  |
| `headingAs` | `HeadingLevel` | Heading element for each item title. |
| `id` | `string` |  |
| `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.

| Prop | Type | Description |
| --- | --- | --- |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `id` | `string` |  |
| `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.

| Prop | Type | Description |
| --- | --- | --- |
| `title` required | `ReactNode` |  |
| `actions` | `ReactNode` | Optional link or button beside a start-aligned header. |
| `align` | `"center" \| "start"` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `description` | `ReactNode` |  |
| `eyebrow` | `ReactNode` |  |
| `headingAs` | `HeadingLevel` | Heading element; `h2` for page sections. |
| `id` | `string` |  |
| `size` | `"md" \| "lg"` | Title size from the display scale. |
| `titleId` | `string` | Id 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.

| Prop | Type | Description |
| --- | --- | --- |
| `children` required | `ReactNode` | The illustrated UI. Build it from Monarch components so it stays on-brand. |
| `label` required | `string` | Accessible description of the illustration, e.g. "Dossier editor with an outline and the Assistant panel". Required: the frame is announced as one image. |
| `backdrop` | `boolean` | A soft accent panel behind the frame, for hero moments. |
| `caption` | `ReactNode` | Visible caption under the frame. |
| `chrome` | `"none" \| "window" \| "browser"` | `window` (app window dots), `browser` (address bar) or `none`. |
| `className` | `string` |  |
| `id` | `string` |  |
| `title` | `string` | Text 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.

| Prop | Type | Description |
| --- | --- | --- |
| `items` required | `StatItem[]` |  |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `id` | `string` |  |

## Variants

| Prop | Values | Description |
| --- | --- | --- |
| `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

| State | Exposed as | Behaviour |
| --- | --- | --- |
| Linked feature hover | `data-linked` | Border strengthens and a medium shadow appears. |
| FAQ item open | `data-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

| Keys | Action |
| --- | --- |
| Tab | Linked feature cards are one tab stop each; FAQ triggers follow. |
| Enter / Space | Opens a linked card or toggles a FAQ answer. |
| Arrow Up / Down, Home / End | Move 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?").

## Related components

- [MarketingHero](https://monarchui.dev/components/marketing-hero/): The section that opens the page.
- [SiteHeader and SiteFooter](https://monarchui.dev/components/marketing-site-shell/): Header and footer around the sections.
- [Accordion](https://monarchui.dev/components/accordion/): The disclosure FAQ is built on.
- [StatCard](https://monarchui.dev/components/stat-card/): Figures inside signed-in dashboards.

## Dependencies

| Kind | Depends on |
| --- | --- |
| npm packages | None |
| Monarch components | [Accordion](https://monarchui.dev/components/accordion/) |

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.

| Check | Covered |
| --- | --- |
| Axe in jsdom | Yes |
| Server rendering | Yes |
| Browser suites | Visual 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`

## All example code

### Section with features

```tsx
import { FeatureGrid, MarketingSection, MarketingSectionHeader } from '@rookcom/monarch-react/marketing';

<MarketingSection spacing="sm" aria-labelledby="ex-features">
  <MarketingSectionHeader
    titleId="ex-features"
    eyebrow="The editor"
    title="Every idea gets the right shape."
    description="Type a slash and pick a block."
  />
  <FeatureGrid
    columns={2}
    items={[
      {
        title: 'Slash commands',
        description: 'Tables, lists and callouts, one keystroke away.',
      },
      {
        title: 'Version history',
        description: 'Named snapshots you can restore safely.',
      },
    ]}
  />
</MarketingSection>
```

### Product frame, stats, FAQ and CTA

```tsx
import { Button } from '@rookcom/monarch-react';
import { CTABand, FAQ, ProductFrame, StatStrip } from '@rookcom/monarch-react/marketing';

<div style={{ display: 'grid', gap: 'var(--mn-space-10)' }}>
  <ProductFrame
    label="Share dialog with a copyable link"
    chrome="browser"
    title="example.rookhq.com/share"
  >
    <p style={{ margin: 0, padding: 'var(--mn-space-6)' }}>
      Anyone with the link can view
    </p>
  </ProductFrame>
  <StatStrip
    items={[
      { value: '3', label: 'Export formats' },
      { value: '13', label: 'Interface languages' },
    ]}
  />
  <FAQ
    items={[
      { question: 'Which formats can I export?', answer: 'HTML, Markdown and PDF.' },
    ]}
  />
  <CTABand
    headingAs="h3"
    title="Start with a blank page."
    actions={<Button variant="primary">Start writing</Button>}
  />
</div>
```
