Section
A full-width band that owns the vertical rhythm and the background behind a group of a page's content.
A section is the band a page is divided into: a full-width strip that claims vertical room around its content, paints one of three backgrounds behind it, and optionally holds the content to the framework's column. It is how a page states "this is one part of me, and the next part starts here".
It owns the rhythm and the surface, and it deliberately does not own the width unless asked:
Container is the width on its own, and Section composes either way round, a section can
contain a container, or a page can place a container around several sections.
Usage
import { Section, Typography, VStack } from "@asheeui/web";
<Section spacing="xl" background="muted" contained>
<VStack gap="sm">
<Typography role="heading-xl" as="h2">
Everything a campaign needs
</Typography>
<Typography role="body-lg" tone="muted">
Segment, schedule and measure from one place.
</Typography>
</VStack>
</Section>;
The children are laid out by whatever you put inside, the band supplies room around them, not a
gap between them. That is the division of labour: spacing is the band's rhythm, and the rhythm
inside the band is a Stack's.
The band's rhythm
spacing is the vertical padding the band claims above its first child and below its last, and
it is the only vertical space a section adds. A band with spacing="2xl" separates two parts of
a page that are not otherwise related; "md" tightens a page that already has headings doing the
separating.
Pick a token and the band grows around its content without moving it in the reading order. The scale is the shared one, so a section's rhythm and a stack's gap are the same seven words, see Layout and spacing.
Backgrounds and separators
Three treatments, and one separator. none leaves the page background showing through, which is
the right answer for the band a page opens with; muted draws a subdued surface, so a long page
reads as several parts; tinted is a faint accent for the one band that should be noticed, a
pricing table, a closing call to action.
divider draws a rule above the band, which is what keeps two bands of the same treatment from
running together. It is a border on the top edge of the band that asks for it, so the boundary is
drawn once rather than twice by the two bands either side of it.
The three treatments are shared vocabulary rather than a web idea: @asheeui/core declares
SectionBackground, so a hero, a call to action and a section all name one type. muted paints
the theme's secondary at half strength and tinted its primary at five percent, so an
application that recolours those tokens changes every band that asks for them at once.
Contained, or the page's column
contained says whether the band wraps its children in a Container, and containerSize says
which width. It is off by default, so a section is a band and nothing else until you ask for a
column, which is what allows both compositions: a Container inside a full-bleed Section, or
several full-bleed Sections inside one Container in PageContent.
The band's content and its background are independent: a contained section paints its
background the full width of the window and holds only the content to the column, which is the
shape a coloured band with a centred headline takes. Turning contained off keeps the children
where they are in the document and hands the width decision to the parent.
as decides the element, and the default is a <section>, which is correct while the band
carries a heading. A band that is purely a rhythm and a surface should render as="div", so the
page does not gain an unnamed region.
The section kit
A band, a heading and a row of actions ship together. SectionHeading is the eyebrow, title and
description block the framework's own bands present, ActionGroup renders configured actions
through the public Button, and SkipLink is the first focusable element of a page. They are
public through the @asheeui/web/section-kit subpath rather than the package entry point, so they
are imported from there:
import { Section, VStack } from "@asheeui/web";
import { ActionGroup, SectionHeading } from "@asheeui/web/section-kit";
<Section contained background="muted" spacing="xl" aria-labelledby="workflow-heading">
<VStack gap="lg">
<SectionHeading
eyebrow="Workflow"
title="Everything a campaign needs"
description="Segment, schedule and measure from one place."
titleId="workflow-heading"
size="lg"
titleAs="h2"
/>
<ActionGroup
primaryAction={{ label: "Start free", href: "/signup" }}
secondaryAction={{ label: "Read the docs", href: "/docs" }}
/>
</VStack>
</Section>;
titleId exists so the band can name itself with aria-labelledby; the heading's level is the
caller's, because a size chooses a typography role rather than a place in the outline.
SkipLink is the other half of that arrangement, the way into the content past repeated
navigation. It takes the id of the region it leads to, which is expected to be focusable, so
following the link moves the reader into the band rather than only scrolling to it:
import { SkipLink } from "@asheeui/web/section-kit";
<SkipLink targetId="campaigns" label="Skip to campaigns" />;
<Section id="campaigns" tabIndex={-1} aria-labelledby="campaigns-heading">
…
</Section>;
Props
All five of the section's options are registered by the component, spacing: "lg",
background: "none", contained: false, containerSize: "lg" and divider: false, so
components.section in the application configuration restates the band once and every section
follows. Nothing here follows defaultVariant or defaultRadius: a band has no variant and no
corners, and the three backgrounds are the framework's own vocabulary.
The heading block is instance-only, it has no configuration section, because a band states its
own heading rather than inheriting one. size resolves the typography role: md is a section
title, lg and xl are the two sizes a page's leading statement takes.
A configured action is a description rather than a React element: label is the only required
field, href makes it a link and omitting it makes it a button, and the remaining fields map
onto Button's own props. The primary action renders solid and the secondary bordered unless
the action states a variant of its own, and children is where an action that needs a handler
goes, because a configured action describes a destination.
targetId and label are both required: a skip link without a destination does nothing, and one
without wording has no accessible name. The classes that hide it until it is focused are exported
as SKIP_LINK_CLASS if you need to place it yourself.
Accessibility
<section>is announced as a region only when it has an accessible name. Give the band a heading and pointaria-labelledbyat it,SectionHeading'stitleIdis there for exactly that, or renderas="div"so the page does not gain an unnamed region.- The band itself renders no heading and sets no level: a
<section>is not an<h2>. The heading block picks both together fromsize, and its default element is the one the role implies,mdis anh2, whilelgandxlare anh1. StatetitleAswhen the band is not the first statement of the page. ActionGrouprenders each configured action throughButton, so every action keeps its own accessible name, its own activation and the framework's focus ring. The group stacks on a narrow screen and becomes a row from thesmbreakpoint without changing the DOM order.- The background and the divider are decoration. Nothing is conveyed by a treatment alone, so a band whose meaning depends on being noticed still needs a heading that says so.
SkipLinkis visually hidden until it receives focus, and it is the first focusable element of the page. Its target must be focusable (tabIndex={-1}), or following the link scrolls without moving the reader.
The spacing scale, the width tokens and as are shared by every layout; see
Layout and spacing.