Back to Ghost

Patterns

apps/shade/src/docs/patterns-guide.mdx

6.38.01.9 KB
Original Source

import { Meta } from '@storybook/addon-docs/blocks';

<Meta title="Patterns / Patterns Guide" /> <div className="sb-doc">

Patterns

<p className="excerpt">Product-shaped compositions. `PageHeader`, `ListPage`, `KpiCard`, `Filters`, `GhAreaChart`. Patterns compose primitives, components, and recipes with knowledge of how Ghost actually uses them.</p>

Use a pattern when

  • The shape is one Ghost reuses across surfaces (page headers, list pages, KPI rows).
  • You'd otherwise be rebuilding the same chrome from primitives + components every time.
  • The page-type taxonomy on Page Types names it.

What patterns do (and don't)

DoDon't
Expose 3–6 named subcomponents (.Title, .Actions, .Body)Take a prop bag (title, onAdd, columns, emptyText …)
Compose components, primitives, recipesFetch data, own routing, read app context
Carry generic names (PageHeader, KpiCard)Carry surface-specific names (MembersFilterBar)
Stay stable across consumersAdd a prop every time a new consumer needs something

If you find useQuery inside a pattern, the boundary is wrong — bring-your-own state.

Promotion rules and the full decision flow: Layers. Agent rules: apps/shade/AGENTS.md.

Example

tsx
import {PageHeader, ListPage} from '@tryghost/shade/patterns';
import {Button, Table} from '@tryghost/shade/components';

<ListPage>
  <PageHeader>
    <PageHeader.Left>
      <PageHeader.Title>Members<PageHeader.Count>{count}</PageHeader.Count></PageHeader.Title>
    </PageHeader.Left>
    <PageHeader.Actions>
      <PageHeader.ActionGroup>
        <Button>Add member</Button>
      </PageHeader.ActionGroup>
    </PageHeader.Actions>
  </PageHeader>
  <ListPage.Body>
    <Table>...</Table>
  </ListPage.Body>
</ListPage>

Browse the sidebar for the live list of patterns.

</div>