Source: https://monarchui.dev/components/section-header/

Components · Layout

# SectionHeader

Unboxed section title with description, meta, actions, a trailing link and busy state.

@rookcom/monarch-react

Component

## Meta and trailing link

## Usage examples

### Description and actions

### Section with busy state

## Purpose

Titles a section of a page or dashboard without drawing a box around it: a heading, an optional description and meta line, and trailing actions or a "View all" link. With content it becomes the labelled section itself.

### Use when

- A dashboard or detail page is split into sections, each with a title and maybe a count or "View all" link.
- The header row inside a Card needs actions or a link next to the title.
- A section reloads in place and should say so (`busy`).

### Avoid when

- The page title: use PageHeader.
- A titled group of settings with a footer: use SettingsSection.

## Design principles

- Unboxed: it adds no border or background, so it works on the page, inside a Card or in a split pane.
- The heading level is chosen by the page outline (`headingLevel`), never by size; size is `size`.
- Secondary text is quiet: description in muted text, meta smaller still.
- Trailing content stays on the title row while it fits and wraps under it on narrow screens.

## API reference

```tsx
import { SectionHeader, SectionHeaderLink } from '@rookcom/monarch-react';
```

| Export | Kind | Rendering | Root class |
| --- | --- | --- | --- |
| `SectionHeader` | component | server-safe | `.mn-section-header-` |
| `SectionHeaderLink` | component | server-safe | `.mn-section-header-` |

Without `children` it renders `<div class="mn-section-header">` with the header row; with `children` it renders `<section aria-labelledby>` with the row and a `.mn-section-header__body`. The ref goes to the root either way.

`SectionHeaderLink` renders an `<a>` (or your router link with `asChild`) with a decorative arrow.

Generated from the TypeScript declarations of `packages/react/src/components/layout/section-header`.

## Properties

### `SectionHeader`

An unboxed section header: title, optional description and meta line, and trailing actions or a "View all" link. With `children` it becomes the whole labelled `<section>`; without, it is the header row alone (for example inside a Card).

| Prop | Type | Description |
| --- | --- | --- |
| `title` required | `ReactNode` | The section title, rendered as a heading. |
| `actions` | `ReactNode` | Buttons or a menu at the end of the header. |
| `busy` | `boolean` | The section's content is loading or refreshing: sets `aria-busy`, shows a spinner after the title and, with `children`, dims the content. |
| `busyLabel` | `string` | Accessible name of the busy spinner. Default "Loading". |
| `children` | `ReactNode` | The section's content. When given, SectionHeader renders a `<section>` labelled by the heading, with the content under the header. |
| `className` | `string` |  |
| `description` | `ReactNode` | A sentence under the title explaining the section. |
| `headingId` | `string` | Id for the heading, to label something else with it. Generated when omitted. |
| `headingLevel` | `"h2" \| "h3" \| "h4" \| "h5" \| "h6"` | Heading element. Pick the level that fits the page outline. Default `h2`. |
| `id` | `string` |  |
| `link` | `ReactNode` | A trailing navigation link, usually SectionHeaderLink ("View all"). Placed after `actions`. |
| `meta` | `ReactNode` | A short secondary line: a count, a date range, "Updated 5 min ago". |
| `size` | `"sm" \| "md"` | `sm` (default) for dashboard sections, `md` for page sections. |

### `SectionHeaderLink`

The trailing "View all" link of a SectionHeader, with a decorative arrow. Give it text that makes sense out of context ("View all invoices") or an `aria-label`, since a page often has several.

| Prop | Type | Description |
| --- | --- | --- |
| `asChild` | `boolean` | Render the child element (a router link) with this styling. |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `id` | `string` |  |

## Variants

| Prop | Values | Description |
| --- | --- | --- |
| `size` | `'sm'``'md'` | `sm` (default, 14px semibold) for dashboard sections; `md` (16px) for page sections. Exposed as `data-size`. |
| `headingLevel` | `'h2'``'h3'``'h4'``'h5'``'h6'` | The heading element. Default `h2`. |

## States

| State | Exposed as | Behaviour |
| --- | --- | --- |
| Busy | `data-busy, aria-busy="true"` | A small spinner named by `busyLabel` ("Loading") follows the title, and the section content dims to 60% opacity. |

## Interaction behaviour

- No behaviour of its own. Actions and links are ordinary controls in reading order after the title.
- Busy is driven by the product; content stays mounted while it dims.

## Keyboard support

| Keys | Action |
| --- | --- |
| Tab | Moves through the actions and then the trailing link, in source order. |

SectionHeader adds no key handling; the slotted controls keep their own.

## Accessibility

Role

region (with children, via

<section aria-labelledby>

), otherwise none

Accessible name

The heading. Pass

headingId

to label another element with it.

- Choose `headingLevel` so the outline does not skip levels.
- With `busy`, `aria-busy` is set on the root and the spinner is a named status.
- The link arrow is `aria-hidden`; write link text that makes sense alone ("View all invoices").

## Responsive behaviour

- The row wraps: when the title and trailing controls do not fit, the controls move under the text (`flex-wrap`).
- Long titles wrap instead of overflowing (`overflow-wrap: anywhere`), so there is no horizontal scrolling at 320px.

## Theme support

- Text uses `--mn-color-text-default` and `--mn-color-text-muted`; no surfaces of its own, so it inherits the page or card behind it in every theme.
- The link focus ring uses `--mn-color-focus-ring`; the dim transition uses duration tokens, which are zero under reduced motion.

## Do and don't

### Do

- Pick `headingLevel` from the page outline: h2 under the page h1, h3 inside an h2 section.
- Pass `children` when the header titles a whole section, so the section is a labelled region.
- Keep meta short: a count, a period, a freshness note.

### Don't

- Do not use it as the page title.
- Do not use `size="md"` to fake a higher heading level, or a lower level to make text smaller.
- Do not put more than two or three trailing controls; move the rest into a menu.

## Related components

- [PageHeader](https://monarchui.dev/components/page-header/): The page title, with breadcrumbs and page actions.
- [SettingsSection](https://monarchui.dev/components/settings-section/): A titled card of settings rows with a footer.
- [Card](https://monarchui.dev/components/card/): Boxes a section; put a SectionHeader inside it for actions.
- [SectionCard](https://monarchui.dev/components/section-card/): Planned card with a standard header and actions.

## Dependencies

| Kind | Depends on |
| --- | --- |
| npm packages | `@radix-ui/react-slot``react` |
| Monarch components | [Spinner](https://monarchui.dev/components/spinner/) |

## Testing coverage

- Renders title (h2), description, meta, actions and the trailing link; Tab order is actions then link; no region without children.
- With children it is a region labelled by its heading, honouring `headingLevel` and `headingId`.
- Busy sets aria-busy and data-busy and shows a named spinner, and clears when done.
- Forwards the ref, passes attributes through and exposes `size`.
- SectionHeaderLink renders a router link with `asChild`, with a hidden arrow.
- Renders on the server.

| Check | Covered |
| --- | --- |
| Axe in jsdom | Yes |
| Server rendering | Yes |
| Browser suites | Visual baselines: /__gallery; Cross-browser axe: /components/section-header |

Tests: `packages/react/src/components/layout/section-header`

## All example code

### Meta and trailing link

```tsx
import { SectionHeader, SectionHeaderLink } from '@rookcom/monarch-react';

<SectionHeader
  title="Recent invoices"
  meta="12 issued this month"
  link={
    <SectionHeaderLink href="#/components/section-header">
      View all invoices
    </SectionHeaderLink>
  }
/>
```

### Description and actions

```tsx
import { Button, SectionHeader } from '@rookcom/monarch-react';

// PlusIcon: demo icon from the docs site; use your own.

<SectionHeader
  size="md"
  title="Team members"
  description="People who can sign in to this workspace."
  actions={
    <Button size="sm" variant="primary" leadingIcon={<PlusIcon />}>
      Invite
    </Button>
  }
/>
```

### Section with busy state

```tsx
import { useEffect, useState } from 'react';
import { Button, SectionHeader } from '@rookcom/monarch-react';

function BusyDemo() {
  const [busy, setBusy] = useState(false);
  useEffect(() => {
    if (!busy) return;
    const t = setTimeout(() => setBusy(false), 1500);
    return () => clearTimeout(t);
  }, [busy]);
  return (
    <SectionHeader
      title="Traffic sources"
      meta="Last 7 days"
      busy={busy}
      actions={
        <Button size="xs" onClick={() => setBusy(true)}>
          Refresh
        </Button>
      }
    >
      <ul style={{ margin: 0, paddingInlineStart: '1.25rem' }}>
        <li>Search</li>
        <li>Direct</li>
        <li>Referral</li>
      </ul>
    </SectionHeader>
  );
}

<BusyDemo />
```
