Layout

Components never pick a width. The layout hands them one.
Every component fills or hugs the bounds its parent provides. Anything that changes shape measures its own container, never the window. Only app chrome reads the viewport.
DESKTOP · 12 COLUMNSTABLET · 8 COLUMNSPHONE · 4 COLUMNS
Breakpoints · form factors · page grid
base · desktop
Phone
≤ 640
Overlays as bottom sheets · Shells as drawers · Rows stack
Tablet
641 – 1024
Overlays anchored · Shells as drawers · Row spans by measure
Desktop
> 1024
Overlays anchored · Shells as rails · Page capped at 1280
A breakpoint applies at its width and below · unknown width (server, first frame) renders the desktop variant · useBreakpoint() and useFormFactor() are for window chrome only
Live · resize the container
drag the handle or pick a width
container
0px
base
Show sizing
Riskora
Overview
Boards
Members

Overview

Revenue
$128k
Members
1,204
Uptime
99.9%
p95
212ms

Invite people

Name
Email
Role
Team
Members24
  • Ada Lovelace
    Owner
    $12.4k
    Active
  • Grace Hopper
    Admin
    $9.1k
    Active
  • Kira Tanaka
    Editor
    $4.3k
    Invited
  • Noor Park
    Viewer
    $7.8k
    Active
Navbar folds its links into a menu
Stats auto-fit, no JS
Form and table sit side by side
Form fields in two columns
Members table turns into cards
Buttons go block
Same page, same props. The window never changes here: only the container does. Note the form: at Desktop it sits in a narrow column, so it measures compact and stacks its fields.
Sizing contract · every family
v4.0.0 rules
fill
stretches to the bounds it is given
hug
sizes to its content
fixed
intrinsic, never stretches
tiles
auto-fit by a minimum tile width
Family
Width
Height
Floor
Cap
Reflows
Controls
Button · ButtonGroup · Chip · Badge · Kbd
hug
32 · 40 · 48
—
—
Labels never truncate. block turns a hug control into a fill.
Marks
Switch · Checkbox · Radio · Avatar · Icon · Emblem
fixed
own size
—
—
Never reflow; the shape stays put.
Fields
Input · Select · Textarea · Autocomplete · PhoneInput
fill
40 · Textarea grows
—
a measure step
Addons and icons stay; the value column absorbs the change.
Surfaces
Card · Alert · ActionPanel · EmptyState · MediaObject
fill
hug content
—
—
Content wraps inside the bounds it is given.
Tiles
Grid · Stats · GridList · DashboardGrid
tiles
hug
minTileWidth · Stats 150
columns · span
As many equal columns as fit. Spans reflow to narrowSpan, then stack.
Forms
Form · Field · DescriptionList
fill
hug
200 a column
a measure step
Two columns where they fit; stacked otherwise.
Data
DataTable · StackedList · Calendar · Board
fill
hug · scrolls
DataTable 320
—
Table rows stack below their breakpoint. Board columns scroll sideways.
Charts
every chart type
fill
fixed or aspect
—
—
The plot measures its own width; the legend wraps.
Navigation
Navbar · Tabs · Breadcrumb · Pagination · Steps
fill
fixed
—
—
Links fold into a menu when compact; a scrolling bar slides sideways.
Shells
Sidebar · FilterPanel · AppFrame · Page
fixed
fill
—
page step
Viewport tier: a rail above lg, a drawer at and below it.
Overlays
Dialog · Drawer · Popover · ActionSheet · Wizard
fill
hug · body scrolls
—
their own step
Viewport tier: a bottom sheet on phones.
Floors are minWidth plus wrapping, never a fixed width · caps are Container steps · a nested surface is never wider or rounder than what holds it
How a component finds its size
try in this order
1
Intrinsic · no JavaScript
Fill or hug inside the parent's bounds, a minWidth floor, wrapping. Correct on the first frame and on the server.
<Grid minTileWidth={240}> · <Row wrap> · <Row stacks>
2
Container measurement · its own width
A component that changes shape measures itself against the shared breakpoints, so every family flips at the same widths.
useContainerBreakpoint({ base, md, sm }) · first frame renders base
3
Viewport · chrome only
Only window-level chrome reads the window: Sidebar and FilterPanel drawers, phone sheets, app shells.
useBreakpoint() · useFormFactor() · BreakpointOverride for previews
no width at a call site
no window reads in a component
no style escape hatch
DashboardGrid
12 columns · spans in twelfths
Revenue
span 8
Seats
4
1,204
Uptime
4
Latency
4
Errors
4
Funnel
5
Members
7
wide
honors every span
narrow
reflows to narrowSpan
phone
stacks full width
<DashboardGrid> measures its own width, never the window · each widget declares span and narrowSpan in twelfths
Layout · Row & Column · Container · Grid · Divider
no raw flex at a call site
Gap scale
flush
0
tight
4
snug
8
cozy
12
relaxed
16
loose
24
<Row cozy alignCenter between> · <Column tight> · <Row stacks>
Container steps
xxs
sm
lg
xxl
wide
page
13 steps, xxxs 192 → page 1280 · caps and centers, never a raw width
Grid
<Grid minTileWidth={72} columns={3}> + <GridItem> · measures its own width: the fourth tile wraps; 3-up, 2-up, 1-up
View
Text
Pressable
ScrollView
TextInput
React Native primitives, re-exported as-is. They take plain style objects and no skin; everything above them is Canvas.
Divider
<Divider /> · <Divider>or</Divider> · <Divider vertical> · a hairline, never a grey
AppFrame · Page
safe areas · banner · capped page
Riskora
Boards
Reports
banner
banner region
page gutters
safe-area insets, all four edges
<AppFrame> mounts safe area + overlay host · <Page> is one screen