Skip to content
buttery

v1.0.0

Source on GitHub

Version 1.0.0

Surface and nesting

How surfaces nest, with concentric corners and even insets, and the Surface primitive that does it.

A surface is a region with a background, an edge and a radius, such as a panel, a section well or a card. Nest surfaces with Surface, and each inner one takes its corners from the one around it, so a screen of nested regions reads as one shape.

The nesting recipe

  1. Panel, section, card

    buttery's screens nest a few levels deep: a panel on the app background, a section well inside it, and cards inside the well, each with rows inside.

  2. Corners are concentric

    A child's radius is its parent's radius less the parent's padding, which radius="auto" works out. The one deliberate exception is a section, which is sized from the card inside it.

  3. Insets are even

    A nested surface sits evenly inside its parent, with the same inset on every open side.

  4. Titles line up

    A section's title starts on the same edge as the rows inside it.

In code, each level is a Surface, and the card takes radius="auto":

tsx

import type { ReactElement } from "react";
import { Stack, Surface, Text } from "@butteryui/core";

export function Settings(): ReactElement {
  return (
    <Surface level="panel">
      <Surface level="section">
        <Stack gap={2}>
          <Text variant="control">Notifications</Text>
          <Surface level="card" radius="auto">
            <Text variant="label">Email me when an order ships</Text>
          </Surface>
        </Stack>
      </Surface>
    </Surface>
  );
}

Here is the recipe at full size, in an editor's inspector:

Spring launch

Your canvas is empty

Start a fresh card, or open one from your library.

Surface

When to use it

Use it for

  • Panels, sections, cards, floating menus and dialogs
  • Nesting surfaces with concentric corners (radius="auto")

Not for

  • Drawing a box with custom shadows or radii: pick the level that fits

Examples

Floating menu

The floating level used by menus and popovers, holding a short list.

WideSquareTall

Nested section

A panel holding a section whose card nests with concentric corners.

Background
Fill

Variants and states

Levels

Background, edge, shadow and radius for each level.

app
panel
section
card
raised
floating
dialog
inset

Concentric nesting

Each inner surface uses radius="auto": the parent's radius minus its padding.

Dialog 18 → section 10 → card 4

Never less than 4px.

Props

Surface

PropTypeDefaultDescription
levelSurfaceLevel"card"Background, edge, shadow, corner radius and padding, by level. Defaults to "card".
radius"auto" | RadiusTokenCorner radius. "auto" nests concentrically inside the surface around it: the parent's radius minus the parent's padding, never less than 4px. Defaults to the level's own radius.
padSpaceValuePadding on every side, on the spacing scale. Replaces the level's padding.
padXSpaceValueLeft and right padding, on the spacing scale.
padYSpaceValueTop and bottom padding, on the spacing scale.
asChildbooleanRender the single child element instead of a div, with Surface's props merged onto it.

It also takes ComponentPropsWithRef<"div">.

Accessibility

No role of its own; add a landmark role or aria-label when a surface is a region the user navigates to.

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 and padding. The padding comes from its level (8px for panel and dialog, 6px for floating, a 4px well on three sides for section, none for the rest) unless pad, padX or padY replace it. With radius set to auto, its corners take the parent surface's radius less that surface's padding, never under 4px. It has no hit area of its own: to make one pressable, put a Pressable inside it with asChild.

  • Elevation

    Surface levels, from the app's background to dialogs, and the shadows that set them apart.

  • Radius

    The corner radius scale, and how nested surfaces keep their corners concentric.