Figma-style corner smoothing for the web. Backgrounds, borders, shadows, and hover states stay in your CSS. No extra wrapper, optional React and Svelte integrations, and no runtime dependencies in the geometry or DOM packages.
npm install squircles.button {
background: #242424;
color: white;
border: 1px solid #666;
border-radius: 12px;
--squircle-smoothing: 1;
padding: 12px 20px;
}React (18 or later):
import { Squircle } from "squircles/react";
<Squircle as="button" type="button" className="button">
Learn more
</Squircle>Svelte as an action:
<script>
import { squircle } from "squircles/svelte";
</script>
<button class="button" use:squircle>Learn more</button>JavaScript, Vue, or other frameworks through the DOM entry point:
import { applySquircle } from "squircles/dom";
const element = document.querySelector<HTMLElement>(".button");
const cleanup = element ? applySquircle(element) : () => {};
// Call when the element is removed.
cleanup();The integrations read border-radius and --squircle-smoothing from CSS.
Class, style, and size changes, along with hover and focus, update the shape.
Server-rendered elements initially use their ordinary CSS radius.
import { createSquirclePath, createSquircleClipPath } from "squircles";
const options = { width: 200, height: 96, radius: 24, smoothing: 1 };
const path = createSquirclePath(options);
const clipPath = createSquircleClipPath(options);radius supports individual corners; smoothing ranges from 0 to 1.
When space is limited, smoothing is constrained as in Figma.
preserveSmoothing: true keeps it by compressing the control points.
inset moves the path inward, for example by half an SVG stroke width.
- Borders must be solid and uniform; different borders per side are not supported.
- Focus outlines and inset shadows still follow
border-radius. - Images and inputs receive a clip path that also clips their border and shadow. Use a wrapper when needed.
- For semi-transparent borders, use
SquircleSurfacefromsquircles/react. - Without
ResizeObserver, measurement runs on startup and window resize. Other layout changes require a polyfill.
Integration, options, and migration · Architecture and limits
npm ci
npm run check
npx playwright install chromium
npm run test:browser
npm run playgroundPlayground: localhost:5173, React:
localhost:5173/react, Svelte:
localhost:5173/svelte.
npm run screenshots regenerates the README images with transparent shadows.
npm run visual:fixture creates more geometry examples in .artifacts/.
Commits on main follow Conventional Commits.
release-please opens a release PR; merging it publishes the npm package.

