Separator · Scroll area · Resizable handle · Aspect ratio
Aspect ratio — a box that keeps its proportion whatever fills it: a card’s media, an image slot, a video.
Beta · Navigation and overlay · packages/css/src/components/layout-utilities.css
.pui-separator (--vertical --strong) · .pui-scroll-area · .pui-resizable-handle (--horizontal, __grip) · .pui-aspect-ratio (--4-3 --1-1). No decorative separators — only where a line has to be.
Sizes across, states down.
Aspect ratio — Beta
Section titled “Aspect ratio — Beta”- Ratio: 16:9 · 4:3 · 1:1; 320 wide in the specimen — resize keeping the ratio (a 16:9 at 368 is 207)
- No states; a loading media box is Skeleton’s block
Use when an image or a video sits in a layout that must not jump when it loads — a Card’s media, a gallery, a hero’s figure.
Do not use when the image has its own natural size and the layout can wait (an inline illustration); for an avatar (Avatar); for a logo (Logo/*).
Relates to Card, Skeleton, Avatar, Image card (site), Carousel.
Anti-patterns an image squeezed into the wrong ratio · a ratio per screen for the same media · a fill changed on the instance.
Keywords: aspect ratio, media box, image placeholder, 16:9, thumbnail
Figma — page Layout utilities: Aspect ratio (3 variants)
shadcn: aspect-ratio
Resizable — Beta
Section titled “Resizable — Beta”Resizable handle — the seam between two panes the user can drag.
- Orientation: vertical (the seam between side-by-side panes) · horizontal; Has grip
- 240 long in the specimen; stretches with its panes (constraints)
- No states drawn: the line takes border/strong while dragged, in code
Use when two panes share a screen and the user’s balance between them matters — a chat and its context, a list and its detail, an editor and its preview.
Do not use when the panes have one right width (a fixed layout); on a phone; for a sidebar (Sidebar has its own width).
Relates to Chat pattern, Sheet, Scroll area, Separator, Sidebar.
Anti-patterns a handle with no minimum pane width behind it (code) · a grip on every handle (only where the seam is hard to find) · three panes with two handles on a laptop · a fill changed on the instance.
Keywords: resizable, split pane, handle, drag, panel group
Figma — page Layout utilities: Resizable handle (4 variants)
shadcn: resizable
Scroll area — Beta
Section titled “Scroll area — Beta”Scroll area — a region that scrolls inside the page with a bar the system draws: a long list in a panel, a menu that outgrows its height, a table’s horizontal overflow.
- Content (swap — default Slot); Orientation: vertical · horizontal; 320 × 240 in the specimen — stretch it, the viewport and the track follow (constraints)
- No states drawn: the thumb darkens on hover in code (border/strong)
Use when a panel, a sheet, a menu or a card holds more than its height and must not grow — Command’s list, a Sheet’s content, a long Select menu.
Do not use when the page itself scrolls (the browser’s bar, with its gutter reserved); a table wider than its column (Data table’s own overflow); to hide content that should be shorter.
Relates to Slot, Sheet, Command, Select menu, Data table, Resizable.
Anti-patterns a scroll area inside a scroll area · a bar drawn where the browser’s would do · a thumb thinner than 6 · a fill changed on the instance.
Keywords: scroll area, scrollbar, viewport, overflow, scrollable
Figma — page Layout utilities: Scroll area (2 variants)
shadcn: scroll-area
Separator — Beta
Section titled “Separator — Beta”Separator — a line between two things, only where a line has to be.
- Orientation: horizontal (240 in the specimen — stretch it) · vertical (120); Weight: default · strong; 1px
- No states, no text; a labelled divider (‘or’) is a row of Separator + text + Separator in the consumer’s layout
Use when two regions touch and spacing alone does not separate them — a menu’s groups (Dropdown menu’s separator is this), a toolbar’s clusters (vertical), a footer above its content.
Do not use when the eye already sees two things (a card on a page, a heading over a list); under every list row (that is the Table’s own rule); as decoration between sections (spacing does it).
Relates to Dropdown menu, Toolbar (Topbar), Table, Card, Accordion item.
Anti-patterns a separator between every section of a page · a separator plus a background change (one is enough) · a 2px separator outside the Accordion item · a fill changed on the instance.
Keywords: separator, divider, rule, hr, line
Figma — page Layout utilities: Separator (4 variants)
shadcn: separator
The markup — copy this
Section titled “The markup — copy this”The class, the parts, and nothing that is not in the package. The same block opens layout-utilities.css.
<hr class="pui-separator"> <div class="pui-separator pui-separator--vertical pui-separator--strong" role="separator"></div><div class="pui-scroll-area" tabindex="0" role="region" aria-label="…" style="height: 240px"> …content… </div> (a scrollable region is keyboard-reachable)<div class="pui-resizable-handle pui-resizable-handle--grip" role="separator" aria-orientation="vertical"><span class="pui-resizable-handle__grip"><span class="pui-icon">…</span></span></div><div class="pui-aspect-ratio pui-aspect-ratio--4-3"><img src="…" alt=""></div>Accessibility — measured, not assumed
Section titled “Accessibility — measured, not assumed”Every number here is measured on the rendered component: contrast (npm run contrast:render), the focus ring (npm run focus) and the keyboard (npm run keyboard). The floors are principle 12’s.
Contrast
Section titled “Contrast”| ink on ground | reads | floor | the matrix calls it | |
|---|---|---|---|---|
#0b0202 on #ffffff |
20.51 | 4.5 | text.default on surface.page (promised) | ok |
1 distinct pair(s) rendered, 0 that axe calls a violation.
The focus ring
Section titled “The focus ring”| primitive | on | the indicator | over | the change | |
|---|---|---|---|---|---|
| Resizable handle | surface/page | fill #6a66e4 0 px |
#dad9d9 |
3.22 | ok |
| Resizable handle | surface/card | fill #6a66e4 0 px |
#dad9d9 |
3.22 | ok |
| Resizable handle | surface/sunken | fill #6a66e4 0 px |
#dad9d9 |
3.22 | ok |
| Scroll area | surface/page | outline #6a66e4 2 px |
#ffffff |
4.53 | ok |
| Scroll area | surface/card | outline #6a66e4 2 px |
#f2f2f7 |
4.06 | ok |
| Scroll area | surface/sunken | outline #6a66e4 2 px |
#f2f2f2 |
4.05 | ok |
1 of 1 focus stop(s) in this block meet WCAG 2.4.13 on screen — the same crop screenshotted focused and unfocused, and the difference measured.
Keyboard
Section titled “Keyboard”Nothing in this component claims an ARIA role with a keyboard contract; its controls are ordinary ones and the browser already gives them their keys.
Tab order across the whole library is document order over 344 stops, and Shift+Tab is its exact reverse — no keyboard trap anywhere (WCAG 2.1.2).
Pepper UI v1.5.0
The Mobupps design system. 386 tokens, 88 components, 65 pages in the workshop — every page of this site generated from the repository, so nothing here is typed twice.