squircle-corners
v0.1.1
Published
Apple-style squircle corners for React — clip-path backgrounds with reliable SVG strokes
Downloads
29
Maintainers
Readme
squircle-corners
Apple-style squircle corners for React — smooth, continuous curvature (unlike border-radius), with any CSS background and an SVG stroke that follows the same shape.
Based on Figma’s squircle article and figma-squircle.
Why not border-radius?
A rounded rectangle has discontinuous curvature where the straight edge meets the circular arc. A squircle smooths that transition — the shape reads as one continuous form (like iOS app icons), not a square with rounded corners bolted on.
Install
npm install squircle-cornersPeer dependencies: react, react-dom (18+).
Written in TypeScript and ships with types. Plain JavaScript works fine.
Quick start
import { Squircle } from "squircle-corners";
// cornerSmoothing defaults to 0.6 — Apple / iOS 7
<Squircle
borderRadius={24}
strokeColor="rgba(0,0,0,0.12)"
strokeWidth={1}
style={{ background: "linear-gradient(135deg, #667eea, #764ba2)" }}
>
Content
</Squircle>import { Squircle, DEFAULT_CORNER_SMOOTHING } from "squircle-corners";
<Squircle borderRadius={24} cornerSmoothing={DEFAULT_CORNER_SMOOTHING} />Layout
The squircle follows the outer <Squircle> box, not its children.
- Any size works: fixed dimensions,
width: "100%", flex/grid, or content-driven height. - Children (full-width divs, images, stacks) render normally and are clipped to the shape.
- The host needs a non-zero size from CSS or from its content.
- Put
<Squircle>on the element you want shaped — card, button, panel.
How it renders
| Layer | Mechanism |
|-------|-----------|
| Fill / background | clip-path: path('…') on the host |
| Stroke / border | SVG <path> overlay (CSS border cannot follow a clip path) |
Paths use pixel coordinates. A ResizeObserver rebuilds the path when the element resizes.
On SSR, clipping applies after mount once size is known.
API
<Squircle />
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| borderRadius | number | 0 | Corner radius in px (not %) |
| cornerSmoothing | number | 0.6 | Smoothing ξ, 0–1. 0 = rounded rect, 0.6 = Apple default, 1 = max smooth. Out-of-range values are clamped |
| preserveSmoothing | boolean | false | On tight boxes, keep ξ and adjust handles instead of reducing smoothing |
| strokeColor | string | — | Stroke color (enables SVG overlay) |
| strokeWidth | number | 1 | Stroke width in px |
| strokeOpacity | number | 1 | Stroke opacity |
| strokeLinecap | "butt" \| "round" \| "square" | "round" | SVG linecap |
| strokeLinejoin | "miter" \| "round" \| "bevel" | "round" | SVG linejoin |
| as | ElementType | "div" | Polymorphic host (button, a, …) |
All standard DOM props (className, style, onClick, …) are forwarded.
On small boxes, borderRadius is capped at min(width, height) / 2. Smoothing may shrink further unless preserveSmoothing is set.
useSquirclePath(ref, options)
Returns { d, width, height, radius, smoothing, consumption }.
getSquirclePath({ width, height, borderRadius, cornerSmoothing, preserveSmoothing })
Pure geometry — no React, no DOM.
Exports
DEFAULT_CORNER_SMOOTHING—0.6- Types:
SquircleProps,SquirclePathOptions,SquirclePathResult,UseSquirclePathOptions,UseSquirclePathResult
Browser support
Requires: clip-path: path() and ResizeObserver.
| | | |---|---| | Supported | Chrome 88+, Firefox 71+, Safari 13.1+, Edge 79+, modern mobile | | Not supported | IE11 | | Fallback | None — unsupported browsers show an unclipped rectangle |
Stroke uses standard SVG.
Examples
npm install && npm run build && npm run exampleDemo: solid / gradient / image fills, stroke-only, squircle vs border-radius, resizable box, button. Usually http://localhost:5173.
Development
npm run build # ESM + CJS + types
npm test
npm run typecheckReferences
License
MIT
