---
title: "Spacing model"
description: "How composition decides spacing: rich-text rhythm, section padding and when to reach for Stack."
requested_language: fr
language: en
translation_notice: "This page isn't translated yet"
url: https://docs.systhema.app/fr/concepts/spacing-model
version: unreleased (main)
docs_index: https://docs.systhema.app/fr/llms.txt
---
> This page isn't translated yet. Showing English.


In Systhema you rarely set a margin. Spacing follows from how components are nested: content containers space their children from tokens, and an `Article` spaces its sections. This page explains the two mechanisms and the one tool for everything else, `Stack`.

A typical page shell:

```tsx title="src/app/layout.tsx"
import type { ReactNode } from 'react'
import { Article, FooterSimpleInstance, HeaderInstance, SysthemaProvider } from '@systhemaui/next'

export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en" data-theme="default">
      <body className="bg-layout-main">
        <SysthemaProvider>
          <HeaderInstance />
          <main id="main-content">
            <Article>{children}</Article>
          </main>
          <FooterSimpleInstance />
        </SysthemaProvider>
      </body>
    </html>
  )
}
```

Each page then renders `Section`s with headings, paragraphs and components inside, and none of them carries a margin class.

## Rich-text rhythm

Every content container is a rich-text box: it carries the `richtext` class, and the `.richtext > *` rules space its **direct children** from tokens. `Section` wraps its children in `container > richtext`; `Article`, `Card`, `Column`, `Row` and `FeatureContent` carry `richtext` themselves, and the hero content slot uses the same rhythm.

| Direct child                                            | Space above and below                                     |
| ------------------------------------------------------- | --------------------------------------------------------- |
| Heading (`h1`–`h6`)                                     | `1.2ch` above, `0.6ch` below                              |
| Paragraph or list                                       | `0.7lh` each side                                         |
| Quote                                                   | `--typography-block-margin-y`                             |
| Separator                                               | `--typography-block-margin-y` plus `--separator-margin-y` |
| Figure                                                  | 1.5 × `--typography-block-margin-y`, 2 × from `md`        |
| Block component (`Columns`, `Stack`, cards, accordions) | 2 × `--typography-block-margin-y`                         |
| The same block component twice in a row                 | 1 × between them                                          |
| First and last child                                    | no outer margin                                           |

Headings and paragraphs scale with their own font size (`ch`, `lh`), and the block spacing follows the `typography.blockMarginY` token per breakpoint.

## Stack replaces the rhythm

[`Stack`](https://docs.systhema.app/fr/components/stack.md) is a flex container with a token `gap`. Its children are no longer direct children of the rich-text box, so the rhythm stops applying to them and the gap you chose applies instead. That is right for a row of chips, buttons or icons, or a row of cards. It is wrong around prose: the heading and paragraphs in the second band below lose their rhythm.

```tsx preview iframe bleed height=620 title="Rich-text rhythm, then the same content inside a Stack"
import { Chip, Heading, Paragraph, Section, Stack } from '@systhemaui/next'

export default function Demo() {
  return (
    <div className="w-full">
      <Section layoutBackground="main">
        <Heading.h3>Direct children of the section</Heading.h3>
        <Paragraph>Each element is spaced by the rich-text rules, from tokens.</Paragraph>
        <Paragraph>A paragraph gets 0.7lh above and below, a heading 1.2ch above.</Paragraph>
        <Stack direction="row" gap="xs" wrap>
          <Chip>Tokens</Chip>
          <Chip>Rhythm</Chip>
          <Chip>Stack for the row</Chip>
        </Stack>
      </Section>
      <Section layoutBackground="alternative">
        <Stack direction="col" gap="xs">
          <Heading.h3>The same content in a Stack</Heading.h3>
          <Paragraph>The rich-text rules no longer reach these elements.</Paragraph>
          <Paragraph>Only the Stack gap separates them.</Paragraph>
        </Stack>
      </Section>
    </div>
  )
}
```

## Section padding

Between sections, `Article` decides:

- Each `Section` has `--section-padding-y` of padding inside it (`py-section`), and the article adds the same amount as margin around a run of sections. Adjacent sections sit flush, with no margin between them.
- Two adjacent sections with neither a `theme` nor a `layoutBackground` read as one band: the padding between them is removed.
- Two adjacent sections with the same `theme` and `layoutBackground` also merge.
- A section, or a full-width figure, that is the first or last child of the article drops the article's own padding on that side.

So a page of plain sections reads as continuous content, and a section with a background starts a new band. Give one of two neighbours a `layoutBackground` (or a `theme`) when they should read as two. See [Themes and backgrounds](https://docs.systhema.app/fr/concepts/themes.md#backgrounds-and-section-spacing).

## What this means for your markup

- Put headings, paragraphs, lists and block components directly inside `Section`, `Card` or `Column`. Do not wrap prose in a `Stack` or a `div`.
- Use `Stack` for a row of inline elements or of cards. A single button among paragraphs goes inside a `Paragraph`, as the Payload editor produces it.
- Do not fight the rhythm with margin utilities such as `mt-8` or `!mb-0`. If the rhythm is wrong for the whole project, change the token.

## Changing the rhythm

The rhythm and the padding come from `responsiveSizing` tokens, one value per breakpoint. Change them in Figma, or override them in `systhema.config.ts`:

```ts title="systhema.config.ts"
const config: SysthemaConfig = {
  customTokens: {
    responsiveSizing: {
      lg: {
        typography: { blockMarginY: '28px' },
        section: { paddingY: '120px' },
      },
    },
  },
}
```

The relevant tokens are `typography.blockMarginY`, `section.paddingY`, `separator.marginY` and the `gap.*` scale. Write lengths with a unit (`'28px'`); see [Custom tokens](https://docs.systhema.app/fr/design/custom-tokens.md#length-overrides-need-a-unit). How those pixel values become CSS, fixed or fluid, is on [Responsive sizing](https://docs.systhema.app/fr/concepts/responsive-sizing.md).

## Related

- [Stack](https://docs.systhema.app/fr/components/stack.md)
- [Section](https://docs.systhema.app/fr/components/section.md)
- [Section spacing](https://docs.systhema.app/fr/styling/section-spacing.md)
- [Responsive sizing](https://docs.systhema.app/fr/concepts/responsive-sizing.md)
- [Custom tokens](https://docs.systhema.app/fr/design/custom-tokens.md)
