Strata
A page of titled sections, each one explained beside its content. Every section pairs a header — its title and description — with the controls that header describes. Strata.Root stacks the sections with a hairline between them. It is the shape of a settings page, a resource configuration editor, and any form long enough that each group needs its own sentence.
Below the md breakpoint the header stacks above its own content, so a narrow viewport keeps the pairing rather than squeezing two columns into one. The component owns structure only: the grid, the vertical rhythm, and the rules between sections. Form state, validation, and the controls themselves arrive as composed JSX.
Reach for Card when a group needs a raised surface of its own, for Media Object when the thing beside the text is an image or an icon, and for Description List when the pairs are read-only term and value data rather than headed sections.
Each demo below runs in its own framed document, so its media queries track the frame instead of your browser window. Switch the frame to tablet — Tailwind's md boundary, where the split is at its narrowest — and then to mobile, where every header stacks above its own controls.
Composition
Rootis the stack. It rules a hairline between adjacentSectionchildren — never above the first or below the last — and it is the place to set--strata-columnsfor every section at once.Sectionis one titled band. It owns its own vertical rhythm (py-8 first:pt-0) rather than taking it fromRoot, so a single section reads correctly on a page with nothing else on it. Belowmdit stacksHeaderaboveBody; atmdand up it splits them one to two.Headeris the introductory column —TitleandDescription, spaced bygap-2. It renders a semantic<header>, which groups the introductory content of its own<section>; see Accessibility for why that is not a secondbannerlandmark.Titlerenders an<h2>, one level below the page's<h1>. ComposeasChildwhen a page nests its sections deeper.Descriptionis the sentence that says what the section's controls do. Optional — a section whose title says everything may omit it.Bodyis the content column: the controls, cards, or table the header describes. Itsgap-4spaces stacked children, and a consumer's owngap-*replaces it.
Polymorphism
Every part accepts asChild, so the structure composes onto the element a page actually needs. Root renders as the <form> below, which keeps the form element outside every section instead of repeating one per band. Title renders as an <h3> because this section sits under a sub-heading rather than directly under the page <h1>.
Column split
At md and up, Section reads its grid-template-columns from --strata-columns, defaulting to minmax(0, 1fr) minmax(0, 2fr): a one-to-two split whose tracks shrink below their content, so a long single-line value in Body truncates or wraps instead of widening the page. Set the variable on Root to re-split every section at once, or on a single Section to move only that one — custom properties inherit, so the nearest declaration wins. Keep the minmax(0, …) form in an override: a bare 1fr track grows to its content. Below md the variable goes quiet, because the two parts stack in one minmax(0, 1fr) track.
The default suits a short label beside a wide set of controls. When the explanation carries as much weight as the controls, an even split reads better — switch the frame to mobile to watch both splits collapse to the same stack:
Accessibility
- Sections carry no landmark, by design.
Sectionrenders a<section>with no accessible name, so it stays generic in the accessibility tree. ItsTitleheading is the navigation affordance instead. A heading outline can run long and nest deeply; a landmark list only stays useful while it is short enough thatmainandnavare one keypress away. A named<section>is aregionlandmark, so one per section turns that list into a second table of contents the headings already provide. - A landmark does not disambiguate controls. When two sections hold controls that read alike — two radio groups both offering "Allow all" — reach for
Field.SetandField.Legend, which name the group on every control inside it. Assistive technology announces a landmark once, on entry, so naming theSectionfixes nothing here. - Name a
Sectiononly when it is a destination. Passaria-labelledbypointing at theTitle'sidwhen a returning user jumps straight to that section and its container beats its heading as the landing spot — a live log, a status readout, or a chart whose heading is separated from its content by a toolbar. One or two such sections on a page is already a lot. Past that, headings do the job better. - Header is not a second banner.
Headerrenders a<header>, which maps to thebannerlandmark only when its nearest sectioning ancestor is the document body. Nested insideSection's<section>, it is generic, so a page carries as many headers as it has sections. - Heading level is yours.
Titledefaults to<h2>for a section directly under a page<h1>. When the sections sit deeper, composeasChildwith the correct level rather than letting the outline skip — mantle cannot see the surrounding document. - Controls keep their own labels. The
Titleis a heading, not a label. A group of inputs insideBodystill needs its own Field legend or label; a heading above a group names the section, not the control.
API Reference
Strata.Root
The stack of sections. Rules a hairline between adjacent Strata.Section children — never above the first or below the last — and scopes --strata-columns for all of them.
All props from div, plus:
Every part joins an incoming data-slot chain ahead of its own name, so composing a part through an ancestor's asChild yields data-slot="strata strata-section" rather than losing one of the two.
Strata.Section
One titled band of the page. Stacks Strata.Header above Strata.Body below the md breakpoint, then splits the two into a grid at md and up. Carries its own vertical rhythm (py-8 first:pt-0).
All props from section, plus:
Strata.Header
A section's introductory column — its Strata.Title and Strata.Description, spaced by gap-2. Renders a semantic <header>, which is generic rather than a banner landmark inside Strata.Section.
All props from header, plus:
Strata.Title
The section's heading. Renders an <h2>, one level below the page's <h1>. Compose asChild with the right element when a page nests its sections deeper.
All props from h2, plus:
Strata.Description
The sentence that says what the section's controls do. Renders a <p> in muted body text beneath Strata.Title. Optional.
All props from p, plus:
Strata.Body
The section's content column — the controls, cards, or table Strata.Header describes. Its gap-4 spaces stacked children, and a consumer's own gap-* replaces it.
All props from div, plus: