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 — Best for most cases. Only needs radius and smoothing. Works with React/Vue components.
- Dimension-Aware Compute — Use when radius may approach half the element's short side. Automatically constrains to prevent overflow.
- Observer — Use when you want automatic size tracking. No manual calculation needed.
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
--sc-r— Original radius (used for fallback)--sc-i— Compensated radius (used with superellipse)--sc-s—superellipse(K)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.
- Applied radius: 0px
- Compensated radius: 0px
- Resolved smoothing: 0
- Superellipse K: fallback
- Color: ■ Smoothing active ■ Compressed by space ■ No smoothing
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:
- Supported — Uses compensated radius +
superellipse(K)for true smooth corners -
Unsupported — Falls back to original radius with standard
border-radius. Corners remain but without the smooth transition.
All APIs use CSS @supports rules for automatic switching. No polyfills or conditional logic required.