apps/shade/src/docs/primitives-guide.mdx
import { Meta } from '@storybook/addon-docs/blocks';
<Meta title="Primitives Guide" /> <div className="sb-doc">Primitives solve a simple problem: repeated flex/grid/gap class strings hide intent.
Use primitives so that:
Stack: vertical grouping and vertical spacingInline: horizontal grouping, action rows, wrapped inline controlsBox: padding and radius framing without layout semanticsContainer: width constraints and horizontal page paddingGrid: two-dimensional column layoutText: semantic text element + typography rulesFast rule:
StackInlineBoxContainerGridText| Prop | Type | Default | Purpose |
|---|---|---|---|
gap | `none | xs | sm |
align | `start | center | end |
justify | `start | center | end |
| Prop | Type | Default | Purpose |
|---|---|---|---|
as | `div | header | section |
gap | `none | xs | sm |
align | `start | center | end |
justify | `start | center | end |
wrap | boolean | false | Wrap items to multiple rows |
| Prop | Type | Default | Purpose |
|---|---|---|---|
padding | `none | xs | sm |
paddingX | `none | xs | sm |
paddingY | `none | xs | sm |
radius | `none | sm | md |
| Prop | Type | Default | Purpose |
|---|---|---|---|
size | `xs...9xl | prose | page |
centered | boolean | true | Apply horizontal centering |
paddingX | `none | xs | sm |
| Prop | Type | Default | Purpose |
|---|---|---|---|
columns | `1 | 2 | 3 |
gap | `none | xs | sm |
align | `start | center | end |
justify | `start | center | end |
| Prop | Type | Default | Purpose |
|---|---|---|---|
as | `p | span | div |
size | `2xs | xs | sm |
weight | `regular | medium | semibold |
tone | `primary | secondary | tertiary |
leading | `none | snug | normal |
truncate | boolean | false | Single-line truncation |
import {Button} from '@tryghost/shade/components';
import {Container, Inline, Stack, Text} from '@tryghost/shade/primitives';
<Container size="page" paddingX="lg">
<Stack gap="xl">
<Inline justify="between" align="center">
<Text as="h1" size="2xl" weight="bold" leading="heading">Members</Text>
<Button>New member</Button>
</Inline>
<Stack gap="md">
<Text tone="secondary">Core content goes here.</Text>
</Stack>
</Stack>
</Container>
import {Button} from '@tryghost/shade/components';
import {Inline, Stack, Text} from '@tryghost/shade/primitives';
<Stack gap="sm">
<Text as="h2" size="xl" weight="semibold" leading="heading">Posts</Text>
<Inline justify="between" align="center" wrap>
<Text tone="secondary">2,132 total</Text>
<Inline gap="sm">
<Button variant="outline">Export</Button>
<Button>New post</Button>
</Inline>
</Inline>
</Stack>
import {Box, Grid, Stack, Text} from '@tryghost/shade/primitives';
<Stack gap="sm">
<Text as="h3" size="lg" weight="semibold">Drafts</Text>
<Grid columns={1} gap="sm">
<Box padding="md" radius="md" className="border border-border-default">
<Text>Draft row content</Text>
</Box>
<Box padding="md" radius="md" className="border border-border-default">
<Text>Another draft row</Text>
</Box>
</Grid>
</Stack>
// Before
<div className="flex flex-col gap-4">
<div className="flex flex-col gap-2">
<h1 className="text-2xl font-bold">Members</h1>
<p className="text-gray-600">Manage your audience</p>
</div>
<div className="flex items-center justify-between gap-2">...</div>
</div>
// After
<Stack gap="lg">
<Stack gap="sm">
<Text as="h1" size="2xl" weight="bold" leading="heading">Members</Text>
<Text tone="secondary">Manage your audience</Text>
</Stack>
<Inline align="center" justify="between" gap="sm">...</Inline>
</Stack>
// Before
<div className="grid grid-cols-3 gap-6">
<div className="rounded-lg p-4">A</div>
<div className="rounded-lg p-4">B</div>
<div className="rounded-lg p-4">C</div>
</div>
// After
<Grid columns={3} gap="xl">
<Box radius="lg" padding="lg">A</Box>
<Box radius="lg" padding="lg">B</Box>
<Box radius="lg" padding="lg">C</Box>
</Grid>
flex/grid/gap utilities.sm, md, lg) over ad-hoc spacing choices.