Stack
A vertical column of blocks a fixed gap apart, and Section for a titled group.
Overview
Any blocks that follow each other: space is a Stack's gap, never a margin on a block.
Gap
Build 412
Build 411
import { Body, Card, Stack } from "@hackcove/ui";
<Stack>
<Card title="Build 412">
<Body>3 changed</Body>
</Card>
<Card title="Build 411">
<Body>No changes</Body>
</Card>
</Stack>Stack: the gap is one step of the scale, md by default.Build 412
Build 411
import { Body, Card } from "@hackcove/ui";
<div>
<Card title="Build 412">
<Body>3 changed</Body>
</Card>
<Card title="Build 411">
<Body>No changes</Body>
</Card>
</div>div touch each other. Space is the Stack's job, never left to the blocks.Section title
Recent builds
import { Body, Button, Card, Section } from "@hackcove/ui";
<Section title="Recent builds" actions={<Button variant="outline">All builds</Button>}>
<Card>
<Body>Build 412 · 3 changed</Body>
</Card>
<Card>
<Body>Build 411 · no changes</Body>
</Card>
</Section>Section: the title, the actions beside it and the blocks under it, as one named region.Recent builds
import { Body, Button, Card, Cluster, SectionHeading, Stack } from "@hackcove/ui";
<Stack gap="sm">
<Cluster justify="between">
<SectionHeading>Recent builds</SectionHeading>
<Button variant="outline">All builds</Button>
</Cluster>
<Card>
<Body>Build 412 · 3 changed</Body>
</Card>
<Card>
<Body>Build 411 · no changes</Body>
</Card>
</Stack>Section.List
Build 412 · 3 changed Build 411 · no changes
import { Body, Card, Stack } from "@hackcove/ui";
<Stack as="ul" gap="sm" aria-label="Builds">
<li>
<Card>
<Body>Build 412 · 3 changed</Body>
</Card>
</li>
<li>
<Card>
<Body>Build 411 · no changes</Body>
</Card>
</li>
</Stack>Stack as="ul" with an li per item: the spacing of a Stack and a list that assistive tech announces.import { Body, Card, Stack } from "@hackcove/ui";
<Stack gap="sm">
<Card>
<Body>Build 412 · 3 changed</Body>
</Card>
<Card>
<Body>Build 411 · no changes</Body>
</Card>
</Stack>Usage
gapis a scale:xsbetween lines of text,sminside a group,md(default) between blocks,lgbetween groups,sectionbetween a page's top-level blocks (the one responsive page rhythm).widthcaps the column at the left edge:narrow(a reading measure),wide,full, ordefaultfor the parent's width. It is never re-centred.asisdiv(default),section,form,ulorol.as="form"takes the form props and spaces its fields;as="ul"andas="ol"draw no markers and their children are<li>s.- A titled group is a
Section:title,actionsbeside it, then the blocks, at gapsm. It takesgapandwidthasStackdoes. - A row of items is a
Cluster, not a Stack.
Accessibility
Sectionis a<section>named by itstitle(aria-labelledby), so it is a region; with notitlegive it anaria-label.- A
Stackwithas="ul"oras="ol"is a real list: give it anaria-labelwhen more than one list is on the page. as="form"is a<form>; give it anaria-labelor let a heading name it.- A
divStack adds no role.
API
Stack
A vertical column of blocks a fixed gap apart: xs between lines of text (a heading and the line under it), sm inside a group, md (default) between blocks, lg between groups, section between a page's top-level blocks (gap-12, sm:gap-16: the one responsive page rhythm). width caps the column: narrow is a reading measure (max-w-3xl), wide is max-w-5xl, full is the parent's whole width and default sets nothing. A capped Stack starts at its parent's left edge (it is never re-centred), so its first line lines up with every other block on the page. as is a closed set: div (default), section, form, ul or ol. A form takes the form props (onSubmit, action, method, noValidate, ...). A ul or ol is drawn with no markers and its children are <li>s, as in BulletList and Timeline: the Stack does not wrap them, so a child is one list item and Body as="li" or a bare <li> both work.
as- Type
"form" | "div" | "ol" | "section" | "ul"- Default
div
gap- Type
"sm" | "md" | "lg" | "section" | "xs"- Default
md
width- Type
"default" | "narrow" | "full" | "wide"- Default
default
Section
A <section> Stack with an optional SectionHeading title (which names it) and actions beside it.
actions- Type
ReactNode
gap- Type
"sm" | "md" | "lg" | "section" | "xs"- Default
sm
title- Type
ReactNode
width- Type
"default" | "narrow" | "full" | "wide"