Layout

Page regions and groups. The intent decides the element (<main>, <section>, <form>, <ul>, <li>) and the arrangement.

Renders

mainheaderdiv

Intents

Domains

Examples

A form

layout.form renders the <form>, layout.field groups each field, layout.actions holds the buttons.

Preview
<Layout intent="layout.form" className="w-full max-w-sm">
<Layout intent="layout.field">
<Text intent="text.label" as="label" htmlFor="example-name">Name</Text>
<Field intent="field.text" id="example-name" />
</Layout>
<Layout intent="layout.actions">
<Action intent="action.save">Save</Action>
</Layout>
</Layout>

A list

layout.list renders a <ul> and layout.item its <li>s.

Preview
  • Design review

    Tomorrow, 10:00
  • Release planning

    Friday, 14:30
<Layout intent="layout.list" className="w-full">
<Layout intent="layout.item">
<Text intent="heading.item">Design review</Text>
<Text intent="text.meta">Tomorrow, 10:00</Text>
</Layout>
<Layout intent="layout.item">
<Text intent="heading.item">Release planning</Text>
<Text intent="text.meta">Friday, 14:30</Text>
</Layout>
</Layout>

A box about one thing

A box with its own surface is an intent too, not a class.

Preview

Two-step sign-in

Ask for a code from your phone as well as your password.

<Layout intent="layout.panel" className="w-full max-w-sm">
<Text intent="heading.item">Two-step sign-in</Text>
<Text intent="text.body">Ask for a code from your phone as well as your password.</Text>
<Layout intent="layout.actions">
<Action intent="action.start">Turn on</Action>
</Layout>
</Layout>

A notice

A message about the page, with a way to dismiss it.

Preview

Check your email to confirm your address.

<Layout intent="layout.notice" className="w-full">
<Text intent="feedback.info">Check your email to confirm your address.</Text>
<Action intent="action.dismiss" icon={<X aria-hidden className="size-4" />} label="Dismiss" />
</Layout>

Intents it renders

One domain, with its own page of neighbours and examples. The intent decides the element; these are the starter intents.

Layout layout.*

80 intents
  • layout.page

    The main column of an app page, used once per page

    <main>
  • layout.article

    A reading column for a whole page: articles, documents, settings

    <main>
  • layout.task

    A page for one short task, centred on the screen: sign in, reset password, a confirmation. Its headings, text and actions are centred; a form or section inside takes the full width

    <main>
  • layout.header

    The site header at the top of every page: the site name and its navigation

    <header>
  • layout.shell

    The frame of an app with a sidebar: one layout.aside beside the main column. Used once, around the signed-in part of the app

    <div>
  • layout.subnav

    A page with its own section nav beside its content: settings, account, a project’s admin. Put the nav first (a nav of nav.page links), then the content. On phones the nav sits above it

    <div>
  • layout.aside

    Content beside the main column: a docs sidebar, filters, a table of contents

    <aside>
  • layout.footer

    The site footer at the bottom of every page

    <footer>
  • layout.section

    A part of a page made of separate blocks, with or without a title: a section under its heading, the cards in a column, a panel’s contents

    <section>
  • layout.group

    A few closely related elements kept together, e.g. a heading and its text

    <div>
  • layout.headline

    Content at the start of a line and its controls at the end: a section’s title and its button, a panel’s title bar, a list entry with its actions. The controls drop below when the line runs out of room

    <div>
  • layout.labelled

    An icon, avatar or logo beside its text: a person’s photo and name, an icon and its label. The text shrinks and wraps; the icon keeps its size

    <div>
  • layout.form

    A form: renders <form> and stacks its fields

    <form>
  • layout.field

    One form field: its label, input, help text and error

    <div>
  • layout.setting

    One setting changed in place: its label and help text at the start, its switch or menu at the end. Settings pages, preferences

    <div>
  • layout.actions

    Commands side by side: a form’s buttons, a dialog’s choices

    <div>
  • layout.pitch.actions

    The main calls to action under a page’s pitch headline: the install command and the guide beside it, a size up from other buttons

    <div>
  • layout.toolbar

    Controls that act on the content below them: filters, views, refresh

    <div>
  • layout.choices

    The options for one setting, side by side in one track with the chosen one filled: theme, view, units

    <div>
  • layout.meta

    A line of small facts about an item: time, author, counts

    <div>
  • layout.facts

    Labelled facts about the subject of a page, side by side under its title with rules between: profile, status, component. Children are layout.fact

    <div>
  • layout.fact

    One labelled fact in a layout.facts: a text.term above its text.value

    <div>
  • layout.siblings

    Links to the pages beside this one, side by side with the open one filled: the other intents in a domain. One line; scrolls sideways when it overflows, with no scrollbar. Pass data-fade="start", "end" or "both" to fade the edges that hide more. Children are nav.page; pass current on the open one

    <nav>
  • layout.listing

    A code block with the bar above it: what the code is (TSX, Terminal) and a Copy button. Holds a layout.group bar, then one text.code

    <div>
  • layout.table

    Records with the same fields, compared across: members, invoices, API keys. Write plain thead, tbody, tr, th scope="col" and td inside, with no classes; data-off on a tr greys out a row that is switched off. data-head="bar" sets the header row on a bar and pads the outer columns, for a table that runs edge to edge in a panel with no padding. With more columns than fit on a phone, wrap it in a layout.scroller. data-arrival makes its rows rise into place; give each tr a growing animationDelay to stagger them

    <table>
  • layout.scroller

    Content wider than its column, which the reader scrolls sideways: a table with many columns, a long line of code, a board. Give it tabIndex={0} and an aria-label, so keyboard users can scroll it too

    <div>
  • layout.pager

    The row of nav.paging links below a long list or table. Give it aria-label="Pagination"

    <nav>
  • layout.blocks

    An amount shown as a row of blocks, like a battery: the more blocks filled, the more of it. Each block is a layout.blocks.cell, with data-on on the filled ones; data-tone="success", "warning" or "danger" on the row colours them by level. Give it aria-valuenow, aria-valuemin and aria-valuemax

    <div>
  • layout.blocks.cell

    One block of a layout.blocks; data-on when it is filled

    <div>
  • layout.badged

    An icon or avatar with a status dot on its corner: a device and whether it is online. Put the icon first and a text.indicator last

    <div>
  • layout.chart

    A chart: a trend over time, a breakdown. Renders <figure>; put the chart's svg or canvas inside with a height, and a text.caption that says what it shows

    <figure>
  • layout.dock

    A bar that stays at the bottom of the screen while the content under it scrolls or changes: the now-playing bar, a cart total, a long form’s submit button on phones

    <footer>
  • layout.showcase

    A few items side by side where the one in focus takes more of the room: featured photos, picks of the week. On small screens they stack, top to bottom. Children are layout.showcase.item; mark the one in focus with data-active

    <div>
  • layout.showcase.item

    One item in a layout.showcase: its media, then its title and caption. Mark the caption with data-caption: it always takes its room, and shows only on the item in focus, so nothing moves. It rises into view when it appears (stagger them with an animationDelay), widens when it has data-active, and its image keeps its height and crops to fit

    <div>
  • layout.overlay

    Controls drawn over a photo or video, like the arrows in a dialog.media: the buttons inside get a translucent dark backing so they read on any image

    <div>
  • layout.points

    Points made in running text, in no particular order, each a layout.point: the items of a bulleted list in prose

    <ul>
  • layout.steps

    Points made in running text that follow an order, each a layout.point: steps, a ranking

    <ol>
  • layout.point

    One point in a layout.points or layout.steps list, holding its text

    <li>
  • layout.list

    A list of items of the same kind: articles, people, notifications. Children are layout.item

    <ul>
  • layout.item

    One entry in a layout.list

    <li>
  • layout.panel

    A self-contained box about one thing: a sign-in box, a profile summary. Its border is quieter than a layout.teaser’s, since it does not open anything

    <div>
  • layout.feature

    A home page section pairing a pitch with a live demo: a layout.feature.copy and a layout.feature.demo, side by side on wide screens, the copy taking the narrower side

    <div>
  • layout.feature.copy

    The pitch in a layout.feature: its heading, a lead and a link to more, centred against the demo

    <section>
  • layout.feature.demo

    The live demo in a layout.feature, on its own inset panel

    <div>
  • layout.preview

    A live example with its code attached underneath, in one frame with the code block’s edge: a layout.preview.bar, a layout.preview.stage, then a layout.preview.code

    <div>
  • layout.preview.bar

    The bar on top of a layout.preview: what it shows on the left, its copy button on the right, ruled off from the stage

    <div>
  • layout.preview.stage

    Where a layout.preview renders its live example, recessed and centred

    <div>
  • layout.preview.code

    The code under a layout.preview’s stage: its code block sits flush, without its own corners or border, ruled off from the stage

    <div>
  • layout.index

    A bordered box of rows read like a table: props, rules, the intents of a domain. Holds a layout.list of layout.term or layout.situation rows, padded to the box’s edge

    <div>
  • layout.term

    A term and what it means, side by side on wide screens with the term in a fixed column, stacked on phones: a prop, a token, a rule

    <li>
  • layout.situation

    A situation and the intent it calls for, in an "If it is / Use" layout.index. Pass data-current on the row for the page you are on

    <li>
  • layout.teaser

    A box in a layout.collection that previews one page and opens it as a whole: its nav.item title covers the box. Its border reads stronger than a layout.panel’s, and it lifts a level on hover

    <div>
  • layout.marketing

    The main column of a marketing page: the home page, with its own typeface and roomier sections

    <main>
  • layout.command

    A shell command to copy and run: the main call to action wherever it appears. Its copy button covers the whole box, so a click anywhere copies

    <div>
  • layout.registry

    The registry shown behind a demo app, decorative: the entries for what is on screen, the current one lit

    <div>
  • layout.registry.track

    The moving list inside a layout.registry; it slides so the current entry is in view

    <div>
  • layout.registry.entry

    One intent in a layout.registry; data-active on the one the demo points at

    <div>
  • layout.stage

    The backdrop a product demo sits on: a band behind the window, with the layout.registry behind the app

    <div>
  • layout.window

    A framed preview of an app inside a page: a title bar above the app

    <div>
  • layout.window.bar

    The toolbar of a layout.window, drawn like a browser: back, forward and reload, the address, and its controls on the right

    <div>
  • layout.terminal

    A small agent terminal floating over an example app: the conversation and checks that produced it

    <div>
  • layout.terminal.bar

    The title bar of a layout.terminal: window buttons, the title in the middle, its controls on the right

    <div>
  • layout.terminal.log

    The lines in a layout.terminal: the newest at the bottom, older ones fading out at the top. data-still shows a finished run whole, with no fade

    <div>
  • layout.agent

    An agent terminal shown in the page flow, at a fixed height: a layout.terminal.bar, then a layout.terminal.log. data-still lets a finished run set its own height

    <div>
  • layout.tally

    A row of running counts above something that produces them, each a layout.tally.item

    <div>
  • layout.tally.item

    One count in a layout.tally: a text.tally (with a text.delta beside it) over a text.caption naming it

    <div>
  • layout.arrival

    Wraps something that rises into place as it appears, like the cards of a feed. Give each a growing style={{ animationDelay }} to stagger a row of them, and a key that changes to play it again

    <div>
  • layout.band

    A full-width strip a step lighter than the page, edge to edge, for the section a page closes on: the last call to action

    <section>
  • layout.demo

    An example app shown inside a page, in its own theme

    <div>
  • layout.example

    A full example app in the home page’s tabs, in the site font and its own accent

    <div>
  • layout.peek

    Shows the top of something tall, fading out at the bottom: an example app inside its frame on the home page, the frame drawn whole around it

    <div>
  • layout.meter

    An amount within a known range, shown as a filled track: battery, storage used, a quota. Give it aria-label, aria-valuenow, aria-valuemin and aria-valuemax, and one layout.meter.fill inside

    <div>
  • layout.meter.fill

    The filled part of a layout.meter. Set its width to the amount with style={{ width: "62%" }}; data-tone="warning" or "danger" when the amount is a problem, "muted" or "faint" for a value it is compared with

    <div>
  • layout.marker

    Outlines the element an inspector points at, drawn over the page at its position, with its text.marker above. data-mode="outline" draws only a faint dashed outline, for every intent at once

    <div>
  • layout.collection

    Equal items shown side by side as a grid: people to follow, featured sources. It fits as many columns as its own width allows, so it works in a sidebar as well as across a page; set columns from a breakpoint only when the count matters

    <div>
  • layout.notice

    A message about the page that the user can dismiss: check your email, password updated

    <div>
  • layout.loading

    Stands in for content that is still loading: a full-width line of text unless you give it the shape of what will appear

    <div>
  • layout.divider

    A break between two parts of the same content: groups in a menu, sections of a panel. Runs across whichever way its parent flows

    <hr>
  • layout.disclosure

    Content that opens and closes in place under a text.summary line: an FAQ answer, advanced settings

    <details>
  • layout.disclosure.panel

    A layout.disclosure in a bordered box, for a long block of optional detail: its text.summary is a row with a chevron that turns when open, and a line under it separates the content. Pad the content yourself

    <details>

Props

Plus its element’s usual attributes (id, onClick, aria-*, data-*). className is for layout only.

  • intent required

    What this region is: layout.page, layout.form, layout.list...

    LayoutIntent
  • className

    Layout and spacing only: margins, sizes, flex and grid, gaps, padding, text alignment. Visual classes warn in development and fail prongs check.

    string
  • hideBelow

    Hidden on screens narrower than this breakpoint: the desktop half of a region built twice.

    'sm' | 'md' | 'lg'
  • showBelow

    Shown only on screens narrower than this breakpoint: the phone half.

    'sm' | 'md' | 'lg'
  • align

    Pushes the region to that end of its row or column, like a group of controls at the end of a header.

    'start' | 'center' | 'end'
  • ref

    Reaches the rendered element.

    Ref<HTMLElement>
  • unsafeClassName

    Bypasses the intent. Needs a // prongs-unsafe: <reason> comment on the line above, and prongs check counts it.

    string

Rules

  • The only component with a className, and only for layout.

  • Hide or show by screen size with hideBelow and showBelow, and push a region to one end with align, rather than classes.

  • A box that needs its own background or border is a different intent (layout.panel, layout.notice), not a class.

  • Pass onSubmit to a layout.form.