Skip to content
Highlight

FoundationsUpdated Oct 2, 2026

Rounding

Five steps plus two specials, control and pill, climbing slowly so a small control is proportionally less round than a card. Surfaces pick a step by role; controls never pick one at all, because Button, Input and Select take half their height.

Surfaces pick a step. Controls inherit theirs.

tsx
// Surfaces: pick the step by what the surface is<div className="rounded-xl corner-smooth" />    // a card or list item, 16<div className="rounded-2xl corner-smooth" />   // a panel, popover or menu, 20 // Controls: never set a radius. Button, Input and Select take their size's corner<Button size="lg">Save</Button>                  // 32 tall, --radius-size-lg = 12 // Nest concentrically: child radius = parent radius − the gap between them<div className="rounded-2xl p-1">                // 20  <div className="rounded-xl" />                 // 20 − 4 = 16</div> // Pills and dots<span className="rounded-full corner-sharp" />
  • Tailwind names map by role. rounded-lg is the scale's sm, 12px, because that is the job it already did here. Read the table below rather than Tailwind's docs.
  • rounded-sm, rounded and rounded-md are one step. All three resolve to --radius-control, 8px. Write rounded-md in new code.
  • --radius-2xl has no Tailwind name. Nothing maps onto it, so a hero surface at 48px writes rounded-[var(--radius-2xl)]. That names the token rather than a raw value, so it is not the case flagged below.
  • An arbitrary radius is a review flag. rounded-[10px] is either a control size, which the primitive already handles, or a step the scale is missing.

Every surface step as it computes in @highlight/ui.

--radius-control8px
--radius-sm12px
--radius-md16px
--radius-lg20px
--radius-xl24px
--radius-2xl48px
UtilityTokenValueWhere it goes
rounded-md--radius-control8pxCheckboxes and small toggles
rounded-lg--radius-sm12pxInputs, buttons, tags
rounded-xl--radius-md16pxCards, list items
rounded-2xl--radius-lg20pxPanels, popovers, menus
rounded-3xl--radius-xl24pxLarge controls, sheets
None--radius-2xl48pxHero surfaces
rounded-full--radius-pill999pxPills, dots, avatars

A corner that grows slowly with the height, 8 at 20 up to 12 at 32, so a field and a button of one size share a corner.

--radius-size-xs20px tall · 8pxown value
--radius-size-sm24px tall · 9pxown value
--radius-size-md28px tall · 10pxown value
--radius-size-lg32px tall · 12px= --radius-sm
--radius-size-xl40px tall · 20px= --radius-lg
--radius-size-2xl48px tall · 24px= --radius-xl

A control's corner grows more slowly than its height, so a button reads as a softened rectangle beside the fields and cards around it rather than as a pill: 8 at 20, 9 at 24, 10 at 28, then --radius-size-lg meets the surface scale at --radius-sm (12), and xl and 2xl are lg and xl. xs, sm and md carry their own values and stay off the surface scale so a card can never pick them. Despite the shared names, --radius-size-sm is a control size and --radius-sm is a scale step.

A child's radius is the parent's minus the gap. Anything else pinches at the corner.

rounded-2xl · p-1 · rounded-xl20 − 4 = 16. Concentric.
rounded-2xl · p-1 · rounded-2xlEqual radii. The gap pinches at the corner.

Three utilities, and the choice between them is not taste.

css
.corner-smooth   { -electron-corner-smoothing: system-ui; corner-shape: squircle; }.corner-squircle { corner-shape: squircle; }   /* half-height corners: no straight edge to ease into */.corner-control  { corner-shape: var(--corner-control); }   /* Button, fields and list rows: superellipse(1.5) */.corner-sharp    { -electron-corner-smoothing: 0%; corner-shape: round; }   /* rounded-full */
  • corner-smooth on every surface. Electron draws its continuous curve; browsers that support corner-shape draw a squircle.
  • corner-squircle on half-height corners. Electron's smoothing eases into a straight run of edge, and a half-height corner has none, so it reads as a pill.
  • corner-control on controls. A superellipse a little softer than the squircle, for a corner well under half the height. Button, the field shell and list rows already carry it.
  • corner-sharp with rounded-full. A squircle on a clamped radius replaces the round ends rather than softening them.
css
/* packages/ui/src/styles/tokens.shape.css */:root {  --radius-sm: 12px; /* inputs, buttons, tags */  --radius-md: 16px; /* cards, list items */  --radius-lg: 20px; /* panels, popovers, menus */  --radius-xl: 24px; /* large controls, sheets */  --radius-2xl: 48px; /* hero surfaces */  --radius-control: 8px; /* checkboxes and small toggles */  --radius-pill: 999px; /* pills, dots, avatars */} /* packages/ui/tailwind.config.ts maps Tailwind's names onto the scale by role, not by name */borderRadius: {  sm: 'var(--radius-control)',  DEFAULT: 'var(--radius-control)',  md: 'var(--radius-control)',  lg: 'var(--radius-sm)',  xl: 'var(--radius-md)',  '2xl': 'var(--radius-lg)',  '3xl': 'var(--radius-xl)',  full: 'var(--radius-pill)',}