smooth-corners

GitHub Twitter

Converts Figma / iOS corner radius + smoothing into CSS border-radius + corner-shape: superellipse(K).

What is Smooth Corner

Standard border-radius draws a circular arc — curvature changes abruptly where the arc meets the straight edge. Figma (Corner Smoothing slider) and iOS (UIBezierPath with .continuous style) replace the circular arc with a superellipse curve, making the curvature transition continuous rather than abrupt. The smoothing parameter controls the extent of this transition (0 = pure circular arc, 1 = maximum smoothing).

The new CSS property corner-shape: superellipse(K) natively supports this effect. This library converts design tool radius + smoothing values into the border-radius (compensated value) and corner-shape: superellipse(K) that browsers need.


Install

npm i @lixiaolin94/smooth-corners

Pure ESM, zero dependencies, no build step. Three APIs available:


CSS Variable API

smoothCorners(radius, smoothing?) returns a set of CSS custom properties to pair with the .smooth-corners class. The class uses @supports for progressive enhancement: compensated radius + superellipse when corner-shape is supported, original radius as fallback.

Add these rules to your global stylesheet (also available via the smoothCornersCSS export):

.smooth-corners {
  border-radius: var(--sc-r);
}
@supports (corner-shape: superellipse(2)) {
  .smooth-corners {
    border-radius: var(--sc-i);
    corner-shape: var(--sc-s);
  }
}

React

import { smoothCorners } from '@lixiaolin94/smooth-corners';

<div className="smooth-corners" style={smoothCorners(30)} />

Vue

import { smoothCorners } from '@lixiaolin94/smooth-corners';

<div class="smooth-corners" :style="smoothCorners(30)" />

Vanilla JS

import { applySmooth, smoothCorners } from '@lixiaolin94/smooth-corners';

applySmooth(element, smoothCorners(30));

Return value

smoothing defaults to 0.6 (equivalent to Figma's 60% Corner Smoothing). Set to 0 for a pure circular arc, 1 for maximum smoothing.


Dimension-Aware Compute

When you know the element's actual dimensions, computeSmoothCorners(width, height, radius, smoothing) gives more accurate results. It clamps the radius to min(width, height) / 2 and progressively reduces smoothing to 0 when space is insufficient, preventing adjacent corners from overlapping.

import { computeSmoothCorners } from '@lixiaolin94/smooth-corners';

const result = computeSmoothCorners(180, 120, 30, 0.6);
// {
//   radius: 30,             — target corner radius
//   compensatedRadius: ..., — compensated radius computed by the smoothing algorithm
//   k: ...,                 — superellipse exponent
//   smoothing: ...,         — effective smoothing, automatically reduced when space is limited
// }

Observer

The Observer uses computeSmoothCorners under the hood, automatically reading element dimensions and applying CSS custom properties. Supports both declarative (HTML attributes) and programmatic usage. Recalculates automatically when element size changes. Base styles (.smooth-corners rules) are auto-injected on first use — no manual setup required.

Declarative

Add the data-smooth-corners attribute to elements, then import smooth-corners/declarative to enable auto-scanning. Addition, removal, and attribute changes are all captured by MutationObserver.

<div data-smooth-corners="30">...</div>

<script type="module">
  import '@lixiaolin94/smooth-corners/declarative';
</script>

Programmatic

Use observe(el, opts) / unobserve(el) for direct control over individual elements. For manual lifecycle management, import startAutoObserve() / stopAutoObserve() from smooth-corners/observer.

import { observe, unobserve } from '@lixiaolin94/smooth-corners/observer';

observe(el, { radius: 30, smoothing: 0.6 });
unobserve(el);

Playground

Drag the sliders to see computeSmoothCorners output under different sizes and parameters. Notice how smoothing is automatically compressed as the radius approaches half the short side.

Computed CSS

CSS Variable API output


Algorithm

Given original radius r and smoothing s, compute K for corner-shape: superellipse(K).

1. Compensated radius

Smoothing extends the curve outward, requiring a larger border-radius to compensate.

compensated = r · (1 + s)

The dimension-aware version constrains the extension to available space:

extension = min(r · s, limit − r)
compensated = r + extension

2. Superellipse exponent n

The superellipse equation |x|ⁿ + |y|ⁿ = 1 gives a circle when n = 2. Solve for n using a closed-form formula:

d = 1 − 1/√2 ≈ 0.293
u = 1 − (r · d) / compensated
n = ln2 / ln(1/u)

3. CSS K value

Map n to the CSS corner-shape parameter:

K = log₂(max(2, n))

Browser Support

corner-shape: superellipse(...) is a new CSS property (Chrome 138+). All APIs in this library use progressive enhancement:

All APIs use CSS @supports rules for automatic switching. No polyfills or conditional logic required.