Skip to content

Latest commit

Β 

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Space UI logo

@usespaceui/squircle

Figma β€’ iOS style corner smoothing using CSS Houdini Paint Worklet.

Preview β€’ Source Code β€’ SpaceUI.one

Follow @usespaceui


✨ Overview

@usespaceui/squircle brings iOS-style squircles (mathematically perfect superellipses) to your Tailwind CSS projects. It mimics the continuous curvature corners found in Figma and Apple devices. By utilizing the CSS Houdini Paint Worklet API, it provides a native-like performance and seamlessly integrates with Tailwind CSS.


πŸ“¦ Installation

pnpm add @usespaceui/squircle
# or
npm install @usespaceui/squircle
# or
yarn add @usespaceui/squircle

Zero dependencies. Add the plugin to your Tailwind configuration (v3) or your CSS entry file (v4).


πŸš€ Setup

Because the plugin relies on a CSS Houdini worklet to draw the shape, you must initialize the script once in your app.

With React / Next.js

Since the worklet interacts with the browser DOM, initialize it inside a Client Component provider.

// components/SquircleProvider.tsx
'use client'
import * as React from 'react'
import { initSquircle } from '@usespaceui/squircle'

export function SquircleProvider({ children }: { children: React.ReactNode }) {
  React.useEffect(() => {
    initSquircle()
  }, [])

  return <>{children}</>
}

Wrap your root layout:

import { SquircleProvider } from './SquircleProvider'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <SquircleProvider>{children}</SquircleProvider>
      </body>
    </html>
  )
}

With Vanilla JS

Initialize the worklet directly in your client-side entry file:

import { initSquircle } from '@usespaceui/squircle'

if (typeof window !== 'undefined') {
  initSquircle()
}

Configure Tailwind CSS 4

In Tailwind CSS v4, add the plugin directly to your CSS entry point (e.g. globals.css or styles.css):

@import 'tailwindcss';
@plugin "@usespaceui/squircle";

Configure Tailwind CSS 3

Add the squircle plugin to your tailwind.config.js or tailwind.config.ts:

CommonJS (tailwind.config.js)

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ['./src/**/*.{js,ts,jsx,tsx}'],
  theme: {
    extend: {},
  },
  plugins: [require('@usespaceui/squircle')],
}

ESM / TypeScript (tailwind.config.ts or tailwind.config.mjs)

import type { Config } from 'tailwindcss'
import squircle from '@usespaceui/squircle'

const config: Config = {
  content: ['./src/**/*.{js,ts,jsx,tsx}'],
  theme: {
    extend: {},
  },
  plugins: [squircle],
}

export default config

🎨 Usage

1. Sizing

The plugin generates squircle utilities based on your existing Tailwind borderRadius theme. If your Tailwind config has rounded-2xl, you automatically have squircle-2xl.

<div class="squircle-md p-4 bg-black text-white">Space UI Squircle!</div>
<div class="squircle-2xl">...</div>
<div class="squircle-full">...</div>
<!-- Automatically clamped to pill/circle -->

<!-- Arbitrary values are fully supported -->
<div class="squircle-[40px]">...</div>

2. Smoothing Intensity

By default, the plugin applies a 60% smooth transition between the straight edge and the corner arc, perfectly matching Apple and Figma's native smoothing.

You can adjust this intensity using modifiers (/0, /20, /40, /60, /80, /100).

<!-- Maximum smoothing -->
<div class="squircle-2xl/100">...</div>

<!-- Minimal smoothing (closer to a plain rounded rectangle) -->
<div class="squircle-2xl/20">...</div>

<!-- Arbitrary smoothing -->
<div class="squircle-2xl/[25]">...</div>

3. Native Borders (The Magic)

Use standard Tailwind border utilities. The Houdini worklet reads your native CSS border classes and draws the squircle border perfectly. No workarounds needed.

<!-- 8px red border -->
<div class="squircle-2xl border-8 border-red-500 bg-black">...</div>

<!-- 1px semi-transparent blue border -->
<div class="squircle-[30px] border border-blue-500/50 bg-white">...</div>

Note on border placement: By default, the plugin draws the border outside the element (like an outline or a ring) to preserve the interior space for your content. If you want the border drawn inward (standard CSS border-box behavior), you can override the custom CSS variable: <div class="squircle-2xl border-4 border-red-500 [--tw-squircle-outset:0]">...</div>


πŸ›  Advanced: Using with tailwind-merge

If you use tailwind-merge (standard in UI libraries like shadcn/ui for their cn() utility), you should configure it so that squircle-* classes properly override standard rounded-* classes when both are applied.

Extend your merge configuration to group squircle into the rounded class group:

import { clsx, type ClassValue } from 'clsx'
import { extendTailwindMerge } from 'tailwind-merge'

const customTwMerge = extendTailwindMerge({
  extend: {
    classGroups: {
      rounded: [
        { squircle: [() => true] }, // Merges any squircle-* class into the rounded group
      ],
    },
  },
})

export function cn(...inputs: ClassValue[]) {
  return customTwMerge(clsx(inputs))
}

🧰 Utilities Included

  • initSquircle() Registers the CSS Houdini Paint Worklet and sets up the custom CSS properties (--tw-squircle-w and --tw-squircle-smooth). It is safe to call multiple times and fails gracefully in environments where Houdini is not supported.

  • plugin(tailwindcss) The default export is a Tailwind CSS plugin that provides the squircle-* utility classes. It automatically provides fallback border-radius styles for browsers that don't support the Paint API.


Features

  • πŸ’ƒ Native Tailwind Integration: Use utility classes like squircle-2xl just like you would rounded-2xl. No framework-specific wrappers required, and if the browser doesn't support the Paint API, standard rounded fallback values apply automatically.
  • ⚑ Zero-JS Layout Thrashing: Driven by the native CSS Paint API (Houdini). No ResizeObserver, no DOM manipulation, no SVG paths. Repaints happen instantly on the compositor thread.
  • πŸ‘Œ Framework Agnostic: Works in React, Vue, Svelte, Solid, or plain HTML.

πŸ“¦ Related Packages

Package Description
@usespaceui/avatars Generative deterministic avatars
@usespaceui/sounds UI sound effects and audio interactions

πŸͺͺ License

MIT β€” Free for commercial and personal use.


πŸ“š Resources


πŸ›  Maintenance

If you find a bug or have a feature request, please open an issue on GitHub. Engine internals are intentionally not part of the public API.


Space UI Logo
Maintained by the Space UI Team

About

Flawless math-driven squircle masking and geometry rendering for modern UIs.

Topics

Resources

Stars

2 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages