Components · Layout and structure

Section

A titled content container — title, optional description, optional body. Four neutral emphasis levels for in-flow grouping, plus a single admin treatment for staff-only surfaces. Sections never carry categorical accent hues — accents live on Hero blocks, not on the everyday structural primitive.

Documentedby Derek Fidler

Section title

Section description that explains what this group of content is for.

Body content sits below the description.

Default — emphasis 0 + body

Overview

The Section is the standard way to group a block of related content on a page. It adds a title, a soft surface, and an optional description — giving the eye an obvious target without the heavyweight chrome of a card. Reach for it on long-form pages where a heading alone wouldn't carry enough visual separation, but a card would feel boxed-in.

Section, not Card

Use a Section for an in-flow grouping that shares a parent surface. Use a Card when the content is its own discrete unit (a prototype tile, a settings entry). Sections never nest inside other Sections — if you're reaching for that, the page wants a different structure.

Emphasis levels

Four neutral levels of presence on a 0–3 scale. Pick by how much surface the section needs to claim against its neighbours, not by colour preference. emphasis={0} is the default and the right answer most of the time — the heading and the spacing already do the grouping work.

Level 0 — neutral subtlest

The quietest tier and the default. Surface blends into the page; the heading and spacing carry the grouping. Reach for it when the page is already structured by its h2 sections and a Section just needs to give a paragraph or list a name.

Level 1 — outline

A 1 px line frames the group on the page surface without weight. Use when the section is a discrete tile that should read as its own object — settings entries, a single dense table.

Level 2 — neutral subtler

The lightest in-flow fill. Softens a section so neighbours can take the reader's eye on a busy page — the second pass after outline didn't pull enough away from the surrounding content.

Level 3 — neutral subtle

The heaviest neutral. Reads as 'inside' a quieter parent — tertiary chrome inside a tertiary tile, settings under settings. Rarely the right answer at the top level of a page.

No accent hues on Section

The portal stays professional and understated; categorical accents (blurple, green, pink, the rest) belong on Hero blocks and the editorial components, where colour earns its appearance. The everyday Section that does the structural work of a page should never carry hue.

Admin

The single accent exception: admin renders the section on background.accent.yellow.subtlest with the matching deep yellow text colour. Reserve it for surfaces only Flatpay staff see in the portal — refund overrides, internal notes, ledger adjustments. The colour announces the audience, not the tone.

Admin — staff-only

Visible to Flatpay staff only. The yellow-subtlest surface signals the audience, not a tone — never reach for admin to colour an editorial highlight or to add warmth to a normal section.

Refund override

Bypasses the standard 30-day window. Logs to Pulse with the operator's handle.

Body content sits below the description and inherits the same yellow-tinted text colour, so the description never reads as washed grey on a warm fill.

Don't reach for admin to add warmth

adminis semantic. If a section isn’t staff-only, it doesn’t carry yellow, full stop. There is no other accent surface available on Section by design — the structural primitive stays neutral so the rare editorial colour on a Hero or a Testimonial actually lands.

Collapsible

Set collapsible to make the section a disclosure. The title becomes a role="button" with aria-expanded; the description and body collapse into a region governed by aria-controls. Use it for FAQs, advanced-options blocks, and content the user usually skips but might want to peek at.

None. The flat rate covers card networks, processors, and our margin — no surcharges layered on top.

The disclosed region renders the description and the body together. When the section is closed, only the title row stays visible — the rest unmounts cleanly so it doesn't take vertical space.

Composition

The body is anything you want — prose, a list, a small grid, a card rail. The Section provides the framed surface and the heading; what sits inside is your call.

Daily settlements

Funds settle into the merchant's bank account on the same calendar day, every day — no batches, no waiting weekends.

  • Cutoff

    23:59 CET, every day

  • Arrives

    Same day, no batch

  • Weekends

    Yes, both days

Anatomy

Four named parts. The container carries the surface; the title and description belong to the header; the body is opt-in.

Section title

Section description that explains what this group of content is for.

Body content.

  1. Container

    Rounded surface (rounded-lg = 8 px). Carries the emphasis-level background and, on emphasis={1}, a 1 px border.

  2. Title

    Inter Tight 24 / Bold. Sentence case. The only required content — every Section has one.

  3. Description

    Inter Tight 14 / Regular at 60% foreground. Optional but recommended — does the explanatory work the title can't.

  4. Body

    Whatever children you pass — prose, list, grid, embedded component. The padding is uniform: 24 px horizontal, 20 px top/bottom.

Behavior

  • No nesting. A Section never sits inside another Section. Two layers of titled, padded, tinted surfaces is the design-system equivalent of nested cards — read flatten the hierarchy.
  • Sibling sections sit spacing.14 / spacing.16 apart. spacing.14 (56 px) on mobile, spacing.16 (64 px) on desktop. Apply as the top margin on each section after the first — the Tailwind shape is mt-14 md:mt-16 (or gap-14 md:gap-16 on the parent flex / grid). Don't reach for spacing.12 or spacing.20 — the page rhythm depends on this beat being constant.
  • Heading level is an h3. Sections sit one level under the page's h2 sections — they group within a section, not above it. Don't override.
  • Collapsible default is open. defaultOpen={true} — start expanded so the user sees the description on first paint. Pass {false} when the body is genuinely optional or rarely-needed (FAQ items, advanced settings).
  • Description hides when collapsed. When collapsible sections are closed, only the title stays visible — the description and body live in the disclosed region together.

Accessibility

  • Disclosure pattern. Collapsible sections render as a <button> with aria-expanded and aria-controls. The disclosed region is a role="region" with aria-labelledby pointing at the title.
  • Keyboard: the trigger activates on Enter and Space. Tab order continues into the disclosed region when expanded.
  • Color contrast.Description text sits at 60% of the foreground colour. On every surface — including the accent pastels — that pairing meets WCAG AA. Body text uses the variant's inherent foreground (mirrored from the accent token system).
  • Heading semantics. The title renders as an h3. Don't skip heading levels — Section sits one level under the page's h2 blocks, never at the top of a page on its own.

Code

Import from @flatpay-dk/ui. Title is required; description and children are optional.

tsx

import { Section } from "@flatpay-dk/ui";

// Default — emphasis 0, the quietest tier
<Section
  title="Section title"
  description="Section description that explains what this group of content is for."
/>

// Outlined tile — emphasis 1, a defined object on the page
<Section
  emphasis={1}
  title="Daily settlements"
  description="Funds settle into the merchant's bank account every day."
>
  <SettlementsTable />
</Section>

// Heavier in-flow fill — emphasis 2 or 3
<Section
  emphasis={2}
  title="Advanced options"
  description="Softens the section so neighbours can take the eye."
>
  <AdvancedOptions />
</Section>

// Collapsible — disclosure that starts closed
<Section
  emphasis={1}
  collapsible
  defaultOpen={false}
  title="What's a flat rate?"
  description="A predictable percentage on every transaction."
>
  <FlatRateExplainer />
</Section>

// Admin — staff-only surface, yellow-subtlest with yellow text
<Section
  admin
  title="Refund override"
  description="Bypasses the standard 30-day window. Logs to Pulse."
>
  <RefundOverrideForm />
</Section>

Best practices

Three rules cover almost every Section decision.

Settings

The everyday grouping — heading and spacing carry the structure.

Do

Default to emphasis 0 — the quietest tier. Reach for higher emphasis only when the page rhythm needs the section to claim more presence.

What's new

This belongs on a Hero or a Banner — admin colour announces the audience, not the tone.

Don't

Don't reach for admin to add warmth or to highlight an editorial moment. Yellow is reserved for staff-only surfaces.

Do

Pair a collapsible with a closed default when the body is genuinely optional — FAQ rows, advanced settings.

Outer

Inner

Don't do this — flatten the structure.

Don't

Don't nest Sections. Two padded surfaces inside each other is the design-system version of cards-in-cards.

Props

PropTypeDefaultDescription
title*ReactNodeSection heading. Renders as an <h3>. Sentence case; no trailing colon.
descriptionReactNodeOptional supporting line under the title. Sits at 60% foreground; explains what the section groups.
emphasis0 | 1 | 2 | 30Surface presence on a 0–3 scale. 0 (default) = neutral subtlest, blends into the page. 1 = outline (1 px border on the page surface). 2 = neutral subtler fill. 3 = neutral subtle fill (heaviest). No accent hues — Section is intentionally neutral.
adminbooleanfalseRenders the staff-only treatment: yellow-subtlest surface + yellow-tinted text. Overrides emphasis. Reserve for sections only Flatpay staff see in the portal — never as a way to add warmth or highlight.
collapsiblebooleanfalseWhen true, renders the section as a disclosure. The title becomes a button; description and body collapse together.
defaultOpenbooleantrueInitial expanded state for collapsible sections. Pass false when the body is rarely-needed.
childrenReactNodeBody content. Lives below the description when present. Anything you'd put in a normal block — prose, list, grid, embedded component.
...restHTMLAttributes<HTMLElement>All standard section attributes (className, id, data-*, etc.) pass through to the wrapper.