The Squircle Component

Overview

<Squircle> is a dynamic component — it measures its own rendered size with ResizeObserver and re-applies the clip-path whenever the element resizes. Use it for responsive elements whose dimensions aren't known at authoring time.

<script setup>
import { Squircle } from "@squircle-js/vue";
</script>
<template>
<Squircle :corner-radius="24" :corner-smoothing="0.6" class="bg-violet-500 p-6">
<p class="text-white">Hello, squircle</p>
</Squircle>
</template>

Props

PropTypeDefaultDescription
cornerRadiusnumberundefinedCorner radius in pixels. Also written to data-squircle for the noscript fallback.
cornerSmoothingnumber0.6Squircle smoothing from 0 (CSS border-radius) to 1 (maximum superellipse).
widthnumberundefinedExplicit width override. When both width and height are provided, the component skips the ResizeObserver.
heightnumberundefinedExplicit height override.
defaultWidthnumberundefinedFallback width used before first measurement — useful to avoid pop-in on first render.
defaultHeightnumberundefinedFallback height used before first measurement.

All other attributes (class, style, event handlers, ARIA attributes) are forwarded to the underlying <div>.

Reactive props

Props can be driven by refs — the component re-applies the clip-path without re-rendering:

<script setup>
import { ref } from "vue";
import { Squircle } from "@squircle-js/vue";
const radius = ref(16);
</script>
<template>
<input type="range" min="0" max="64" v-model.number="radius" />
<Squircle :corner-radius="radius" class="w-32 h-32 bg-rose-500" />
</template>

When not to use <Squircle>

  • Fixed dimensions: prefer <StaticSquircle> — no observer, lower overhead.
  • Clip arbitrary elements without a wrapper: use v-squircle — skips the extra <div>.
  • Compose with other reactive logic: prefer useSquircle.

Slot

The default slot is rendered inside the clipped <div>. There are no named slots.

<template>
<Squircle :corner-radius="16">
<img src="..." />
<p>Caption</p>
</Squircle>
</template>

Underlying DOM

<Squircle> renders exactly one element:

<div
data-squircle="16"
style="border-radius: 16px; clip-path: path('...');"
>
<!-- slot content -->
</div>

No extra wrappers, no shadow DOM.