Home / Snippets / UI Components /

Rounded corners

Apply consistent rounded corners to UI elements using border-radius with CSS custom properties.

Small 4px
Medium 8px
Large 16px
Extra-large 24px
Asymmetric 4px 24px 4px 24px
Squircle-like min(16px, 30%)
Widely Supported
uino-js

Quick implementation

:root {
  --radius-sm: 4px;
  --radius:    8px;
  --radius-lg: 16px;
  --radius-xl: 24px;
}

/* Apply a token to any element */
.card          { border-radius: var(--radius); }
.chip          { border-radius: var(--radius-sm); }
.dialog        { border-radius: var(--radius-lg); }
.hero-banner   { border-radius: var(--radius-xl); }

/* Asymmetric — each corner individually */
.asymmetric {
  border-radius: var(--radius-sm) var(--radius-xl)
                 var(--radius-sm) var(--radius-xl);
}

/* Squircle-like — clamp to percentage so small elements stay oval */
.squircle-like {
  border-radius: min(var(--radius-lg), 30%);
}

Prompt this to your LLM

Includes role, constraints, two framework variants, and edge cases to handle.

You are a senior frontend engineer building a design token system for a UI.

Goal: Define a border-radius scale as CSS custom properties and apply
those tokens consistently across common UI elements — no JavaScript.

Technical constraints:
- Define four named tokens on :root: --radius-sm (4px), --radius (8px),
  --radius-lg (16px), and --radius-xl (24px).
- Reference every border-radius value in components via var(--radius-*)
  rather than hard-coding pixel values inline.
- Use oklch() for any colors — no hex or rgba values.
- Use CSS custom properties (var(--card), var(--text), etc.) for theming.
- For elements that could become very small (chips, badges), use
  min(var(--radius-sm), 50%) to prevent corners from exceeding the
  element's own dimensions.

Framework variant (pick one):
A) Vanilla CSS — tokens on :root, utility classes like .rounded-sm,
   .rounded, .rounded-lg, and .rounded-xl applied directly in markup.
B) React component — a <Rounded radius="lg"> wrapper that maps the
   prop to the appropriate CSS custom property via an inline style.

Edge cases to handle:
- Very small elements (height < 2 × radius): use percentage or min()
  to avoid "over-rounding" that creates an unwanted oval shape.
- Asymmetric designs: show how to set each corner independently via
  border-top-left-radius etc., or the four-value shorthand.
- Nested cards: the inner element's radius should equal outer radius
  minus the gap — document this optical correction for teammates.

Return CSS only (or a React component if variant B is chosen).

Why a radius scale creates visual consistency

A radius scale works the same way a type scale or spacing scale does: it replaces magic numbers with named, intentional steps. When every component in a UI reaches for var(--radius) instead of a hard-coded pixel value, rounding decisions become a single source of truth. Updating one token propagates the change everywhere, and design-to-code handoff becomes unambiguous — a designer can say "use the large radius" and the engineer knows exactly which value that maps to.

The four-step scale — --radius-sm, --radius, --radius-lg, --radius-xl — covers almost every UI need: sharp-but-soft input fields at 4px, standard cards at 8px, prominent panels at 16px, and hero banners or modals at 24px. Extending the scale is straightforward, and the naming convention makes intent clear without requiring a design system document.

How border-radius works: pixels vs. percentages

border-radius accepts absolute lengths (px, rem, em) or percentages. With absolute lengths, each corner is rounded by a fixed arc regardless of the element's size. With percentages, the radius is calculated relative to the element's dimensions — 50% on a square produces a perfect circle, and 50% on a rectangle produces an ellipse.

The four-value shorthand maps to corners clockwise from the top-left: border-radius: top-left top-right bottom-right bottom-left. You can also use the longhand properties (border-top-left-radius, etc.) for maximum clarity or to target a single corner without disturbing the others.

Percentages become problematic on very small elements. A 16px radius on a 24px-tall chip clips into an unwanted oval. The min() function solves this cleanly: border-radius: min(var(--radius-lg), 30%) takes whichever value is smaller — the absolute radius for large elements, the percentage cap for small ones.

The squircle problem

CSS border-radius produces circular arcs — mathematically a quarter-circle at each corner. The "squircle" (superellipse) that Apple popularised for app icons uses a different curve equation, one where the transition from straight edge to rounded corner is much more gradual. The result feels more natural and less mechanical than a circular arc.

CSS cannot natively produce a true superellipse, but several approximations exist. Using a large radius — around 30% of the element's shorter dimension — creates a corner curve that mimics the squircle's extended shoulder. The min(var(--radius-lg), 30%) approach in this snippet combines both ideas: absolute size for large elements, percentage fallback for small ones, landing in squircle-adjacent territory in both cases.

For cases where a mathematically accurate squircle is required (icon masks, avatar frames), SVG clipPath with a precomputed superellipse path is the only fully correct approach in browsers today. For general UI rounding, the CSS approximation is close enough that users will not notice the difference at typical screen sizes.