Skip to content
buttery

v1.0.0

Source on GitHub

Version 1.0.0

Page grid and containers

The page grid, the content column, sections and centered content, for marketing and content pages.

The page grid is the set of columns, gutters and side padding a marketing or content page snaps to, which changes at 640px and 1024px of the page's width. Build such a page from Page, Section and Container, and its columns, padding and headlines follow the room it has.

The grid

Page widthColumnsGutterSide padding
Under 640px416px16px
640px to 1023px824px24px
1024px and up1224px32px

Content stays at most 1200px wide (--bt-w-page), centered. Visuals may run past the content column to the window's edge; text never does.

Seeing the columns. In development, ⌥⇧G shows the columns over the page.

The parts

  • Page

    The page itself: a column of sections, and the container the grid, the side padding and the display type follow. A page reads the same in a window and in a panel as wide.

  • Section

    A band of the page: room above and below, an optional title and body, and its content in a Container. Its room steps down a size on a phone, so padding never outweighs content.

  • Container

    The content column: at most 1200px wide, centered with padding rather than margins.

  • Center

    Centers its content on both axes in the space it's given, such as an empty state on a stage.

An about page with one large section:

tsx

import type { ReactElement } from "react";
import { Page, Section } from "@butteryui/react";
import { Text } from "@butteryui/core";

export function About(): ReactElement {
  return (
    <Page>
      <Section
        size="lg"
        title="Roasted to order"
        body="Every bag is roasted the week it ships."
      >
        <Text variant="body">Our roastery is in Portland.</Text>
      </Section>
    </Page>
  );
}

App screens. Use AppShell and AppPage instead, with the same side padding.

Page

When to use it

Use it for

  • A landing page, a product page or an article
  • Any page built from Section, SplitHero, Bento and the other page patterns

Not for

  • App screens: use AppShell

Examples

Article page

A single long section of reading on a page, its headline sized by the page's own width.

Designing a title slide

Start with the words. A good title fits on one line, big enough to read from the back of the room.

Landing page

A page as the main landmark, its sections taking turns on the two backgrounds, with prices by the billing period.

Decks that look designed

Write the slides, pick a theme, present.

One price, every feature

$12 a month

Variants and states

Sections on a page

The page is the size container: headlines and padding follow its width, not the window's.

Made for meeting days

One deck for the projector, the call and the inbox.

Kept in step

Undo and redo remember every change.

Props

Page

PropTypeDefaultDescription
asChildbooleanRender the single child element, such as a main, instead of a div, with Page's props merged onto it.

It also takes ComponentPropsWithRef<"div">.

Accessibility

No role of its own. Put what sits between the NavBar and the Footer in a main element and give the bar skipTo with its id, as the marketing template does; on a page with no bar or footer, pass asChild with a main instead.

It takes no keyboard input of its own.

Motion

It doesn't move.

With reduced motion: Nothing changes.

Layout

It takes its container's width as a column of sections on the surface background, and it's the size container the page grid follows: the side padding inside it (16, 24 or 32px) and the display type step up as its own width passes 640 and 1024px. It sets no height, truncates nothing and has no hit areas of its own.

See it in the Halfmoon shop demo.

Section

When to use it

Use it for

  • Each band of a landing or product page
  • Setting a band apart with tone="muted"

Not for

  • Grouping controls in an app: use Inspector.Section
  • A hero: use SplitHero or CenteredHero, which are sections already

Examples

Band sizes

The three sizes and two tones of a band: pick one of each and the band's room and background follow.

Made for meeting days

96px above and below, on the page's surface.

Feature band

A titled band with three equal tiles.

Everything a slide needs

A theme, a background, a layout and speaker notes, all in one panel.

Theme
Background
Layout

New templates

A templates page's band: a heading over this week's three new templates, each added to the library from its card.

New this week

Three templates, each a deck you can make your own.

Quarterly review, 12 slides

Numbers, charts and a summary

Team offsite, 8 slides

Agenda, schedule and a map

Hiring plan, 10 slides

Roles, timeline and budget

0 templates in your library

Quiet band

A small centered band on the app background, between two louder ones.

Kept in step

Undo and redo remember every change.

Variants and states

Heading, body and content

The heading and body sit 48px above the content, 64 once the page is past 1024px.

Everything a slide needs

A theme, a background, a layout and speaker notes, all in one panel.

Theme
Background
Layout

Centered and muted

Kept in step

Undo and redo remember every change.

Props

Section

PropTypeDefaultDescription
size"sm" | "md" | "lg""md"Room above and below: "sm" (64px), "md" (96px, the default) or "lg" (128px).
tone"default" | "muted""default" on the surface, or "muted" on the app background, to set a section apart.
titleReactNodeThe section's heading. It names the section for screen readers.
bodyReactNodeA line or two under the heading.
align"start" | "center""start"Where the heading and body sit: "start" (the default) or "center".
containedbooleantrueWhether the content sits in a Container. Defaults to true; turn it off for full-bleed content.

It also takes Omit<ComponentPropsWithRef<"section">, "title">.

Accessibility

A section landmark named by its heading when it has one; the heading is an h2.

It takes no keyboard input of its own.

Motion

It doesn't move.

With reduced motion: Nothing changes.

Layout

Its height is its content plus its room: 96px above and below by default, 64 with size="sm" and 128 with "lg", and inside a Page under 640px wide the default and "lg" take a step less. It fills its parent's width and puts its content in a Container, at most 1200px wide with the page's side padding; the heading and body wrap, 48px above the content (64 from 1024px of page), or with no gap under them when nothing follows, so they sit in the middle of the band; it has no hit areas of its own.

See it in the Halfmoon shop demo.

Container

When to use it

Use it for

  • Content on a page that isn't in a Section, such as a header row
  • Your own band of a page with contained={false} on its Section

Not for

  • A Section's content: Section already puts it in a Container
  • App screens: use AppShell and its panels

Examples

Full bleed band

A band whose background runs edge to edge while its words stay in the column.

Every deck you make keeps its own history.

Page header row

A row across the top of a page, lined up with the sections under it.

Deckhand

Start a deck

Variants and states

A centered column

At most 1200px wide, with 16, 24 or 32px at the sides as the page passes 640 and 1024px.

Content sits here

Props

Container

PropTypeDefaultDescription
asChildbooleanRender the single child element instead of a div, with Container's props merged onto it.

It also takes ComponentPropsWithRef<"div">.

Accessibility

A plain element with no role; pass asChild to make a landmark of it.

It takes no keyboard input of its own.

Motion

It doesn't move.

With reduced motion: Nothing changes.

Layout

It's as wide as its parent and centers a column at most 1200px wide (--bt-w-page) with side padding rather than margins: 16px a side, 24 from 640px of page and 32 from 1024px, more on a page wider than the column.

Center

When to use it

Use it for

  • Empty states and loading states inside a stage or panel

Not for

  • Centering text inside a control: controls already center their content

Examples

Loading panel

A short status message in the middle of a panel while its content loads.

Loading your decks…

Stage empty

A stage that holds its empty state in the middle, and then the slide that takes its place.

Your canvas is empty

Add a slide, or open a deck from your library.

Variants and states

Both axes

Content sits in the middle of whatever space Center gets.

Centered

Props

Center

PropTypeDefaultDescription
asChildbooleanRender the single child element instead of a div, with Center's props merged onto it.
padSpaceValuePadding on every side.
padXSpaceValueLeft and right padding. Wins over pad on those sides.
padYSpaceValueTop and bottom padding. Wins over pad on those sides.

It also takes ComponentPropsWithRef<"div">.

Accessibility

No role of its own.

It takes no keyboard input of its own.

Motion

It doesn't move.

With reduced motion: Nothing changes.

Layout

It's as wide as its parent and as tall as its content, or as tall as the height it's given, such as 100% of a sized panel. Its content sits in the middle on both axes and is never wider than Center. It has no hit area of its own.

  • Responsive

    Why buttery components respond to their container rather than the window, and how to do the same.

  • App shell

    The frame of a whole app, as an editor or a dashboard, and the page that goes in it.