Shape
Why the corners in a health product are superellipses rather than circular arcs, what shape is allowed to mean, and the one thing it must never carry.
Overview
Shape is the smallest foundation and the one with the largest gap between how much it matters and how much thought it usually gets. It comes down to two decisions: how big the corners are, and what curve they are made of.
The second is the interesting one. A CSS border-radius draws a circular arc,
and a circular arc meets a straight edge with a discontinuity: the curvature
jumps from zero to its full value at a single point. At a 4px radius nobody
notices. At the 16 to 28px radii a generous, iOS-idiom health product actually
uses, the eye reads that discontinuity as a pinch. The corner looks tighter
than it is, and a row of cards looks slightly wrong in a way most people cannot
name.
A squircle is a superellipse, and it distributes the curvature continuously
into the straight edge instead. It is the shape Apple's platform UI has used
for years, and until recently the web could not draw it without an SVG mask or
a clip path.
The CSS corner-shape property changes that, and opsinjs uses it as pure
progressive enhancement: browsers that have it get squircles, browsers that do
not get an ordinary rounded rectangle at the same radius. The difference is
taste, never function.
Shape is often confused with elevation. A rounder card is not a raised card. Depth is material and layer; shape is geometry.
How it works
Three pages sit under this one: the radius scale, which is a
ladder derived from a single value plus the rule for nesting one radius inside
another; Squircle, which is the corner-shape mechanism and its
degradation; and the generated tokens.
Two rules run across all three.
1. Radius is a ladder, not a set of choices. Every radius in the system is derived from one root value by a fixed multiplier, so changing the character of the product from square to generous is one number rather than a search. The rungs are named for the size of thing they belong to rather than for their value. Those things are a control, a card and a sheet.
2. Shape never carries clinical meaning. A rounder card is not a friendlier result. A sharper corner is not a more serious one. Radius may express what kind of object something is, and it may express nothing at all about the value inside. A pill-shaped chip reads as a label, and a large-radius sheet reads as a surface that came from the bottom edge. Status is colour, icon and word, always and only: see Principles.
There is a corollary worth stating separately, because it is the one people break: do not use a full radius to mean "small". A fully rounded pill and a large-radius card are different objects, not different sizes of the same one.
Using it
Match the rung to the object, then stop. Controls take the small rungs, cards the middle, sheets and modal surfaces the large. If you are choosing between two adjacent rungs, the difference does not matter and the smaller one is usually right.
Nest concentrically. An inner radius equals the outer radius minus the padding between them. Get this wrong in either direction and the gap between the two curves visibly varies around the corner. The full rule and the failure cases are on Radius scale.
Do
A result card at the card rung, containing a range bar inset by one space step, with the bar's radius reduced by that step. The two curves stay parallel all the way round the corner.
Don’t
The same card with the inner element at the same radius as its parent. At the corner the gap between them pinches to nothing on the diagonal, which reads as a rendering fault rather than a design choice.
Do not square a corner for emphasis. Emphasis on a health screen is a status question. A squared-off urgent card is a second escalation channel that nobody can read and that disappears in a screenshot.
Do not animate a radius. It is expensive to composite, it draws attention to the container rather than the content, and it is one of the more reliable ways to make a transition look broken part-way through.
Do not reach for the squircle on every rounded box. The corner shape is not
applied globally and no component stamps an attribute for it. Each surface that
wants it opts in by carrying an inline corner-shape property that reads
var(--opsin-corner-shape) beside its radius, which is how Card, Callout and
Dialog draw it. Keeping it to the surfaces the system draws leaves third-party
components, embedded content and anything with an incidental radius alone, and a
browser without support simply keeps the ordinary rounded rectangle.
Tokens
The root radius, the ladder multipliers, the named rungs and the corner shape
itself are generated from tokens/shape.json by scripts/build-tokens.mts. The
full table with a rendered specimen per rung is on
Shape tokens.
| Token | What it controls | Used by |
|---|---|---|
| --opsin-radius-base0.875rem | The one radius the whole ladder is derived from. | accordion, alert-banner, button, callout, card, care-card, combobox, empty-state, field, menu, metric-tile, popover, questionnaire, radio-group, range-bar, reading-input, result-card, scale-input, segmented-control, select, skeleton, symptom-picker, tab-bar, textarea, timeline-entry, toast, tooltip, trend-sparkline |
| --opsin-radius-none0rem | Full-bleed media and anything that meets a screen edge. | no component |
| --opsin-radius-xs0.25rem | The floor for a nested corner. Tags inside a chip, a swatch inside a legend. | popover, range-legend, surface, symptom-picker, term, tooltip |
| --opsin-radius-sm0.4375rem | Inputs and small controls inside a card. | card, checkbox, combobox, consent-sheet, dialog, divider, field, log-sheet, menu, number-field, progress, reading-input, scroll-area, select, sheet, skeleton, slider, switch, tab-bar, tabs, toast, visually-hidden |
| --opsin-radius-md0.875rem | The default. Buttons, chips, cards. | alert-banner, button, callout, card, combobox, empty-state, menu, metric-tile, popover, questionnaire, radio-group, result-card, scale-input, segmented-control, select, skeleton, symptom-picker, tab-bar, textarea, toast, tooltip |
| --opsin-radius-lg1.3125rem | Cards on a phone, where the card is nearly the width of the screen. | accordion, card, combobox, disclaimer-note, menu, popover, result-card, scroll-area, segmented-control, select, surface, toast |
| --opsin-radius-xl1.75rem | Sheets and dialogs. Applied to the leading edge only when the surface meets a screen edge on the other side. | alert-banner, dialog, sheet |
| --opsin-radius-inner-cardmax(calc(0.875rem - 5 * var(--spacing)), var(--opsin-radius-xs)) | A box inside a card at the comfortable density (card padding p-5). | no component |
| --opsin-radius-inner-card-compactmax(calc(0.875rem - 4 * var(--spacing)), var(--opsin-radius-xs)) | A box inside a card at the compact density (card padding p-4). | no component |
| --opsin-corner-shapesuperellipse(4) | The squircle curvature. Degrades to `round` where corner-shape is unsupported. | alert-banner, callout, card, dialog, metric-tile, result-card, sheet |
| --opsin-border-hairline1px | Every boundary in the system by default. | button, surface |
| --opsin-border-emphasis2px | The boundary of a surface carrying `attention` or `urgent`, where the boundary is one of the three non-colour carriers of the status. | disclaimer-note, field, surface |
| --opsin-border-focus2px | The focus ring. Always 2px with a 2px offset, always in a colour measured against both the surface and the page behind it, and never removed. See /docs/accessibility/keyboard-and-focus. | accordion, body-map, button, card, checkbox, combobox, consent-sheet, link, menu, number-field, popover, questionnaire, radio-group, scale-input, scroll-area, segmented-control, select, slider, switch, symptom-picker, tab-bar, table, tabs, term, textarea, toast, tooltip |
| --opsin-border-focus-offset2px | Offset for the focus boundary. | accordion, body-map, button, card, checkbox, combobox, consent-sheet, link, menu, number-field, popover, questionnaire, radio-group, scale-input, scroll-area, segmented-control, select, slider, switch, symptom-picker, tab-bar, table, tabs, term, textarea, toast, tooltip |
Accessibility impact
Shape has less accessibility surface than any other foundation, and exactly three things on it matter.
- A radius can eat a touch target. A heavily rounded control has less clickable area at its corners than its bounding box suggests. The 44pt floor from Density and touch is measured on the interactive area, not on the visual box, and a large radius on a small control is the most common way that measurement quietly fails.
- A radius can eat a focus ring. The focus outline follows the border radius, and where a control is clipped by an ancestor with a smaller radius the ring is clipped with it. This is why the focus indicator is drawn outside the box with an offset. The rule is on Interaction states.
- Shape must never be an information channel, because it survives no assistive technology at all. There is no way to announce a corner. Anything a radius is carrying is information a screen-reader user does not have.
Radius does not affect contrast, so nothing on this page is measured; the
corner-shape support matrix is published by <BrowserSupport> on
Squircle.
Related
- Radius scale has the ladder, the rung names and the nesting rule.
- Squircle covers
corner-shape, the superellipse parameter and the documented degradation. - Materials is the foundation that shape is most often confused with, and the one that actually carries depth.
Typography tokens
The generated reference for every type role, with a rendered specimen for each. Each entry lists the role's size, line height, tracking and weight.
Radius scale
A ladder of rungs derived from a single root radius, named for the objects they belong to, plus the nesting rule that keeps concentric corners parallel.