No-JavaScript Fallback

The problem

@squircle-js/react relies on JavaScript to measure element dimensions and compute the SVG clip-path. When JavaScript is disabled or hasn't loaded yet, the element will have no clip-path applied, leaving it unstyled.

To handle this gracefully, the library ships SquircleNoScript.

How SquircleNoScript works

SquircleNoScript renders a <noscript> block containing a CSS rule:

[data-squircle] {
clip-path: none !important;
border-radius: attr(data-squircle) !important;
}

Every Squircle component writes the cornerRadius value to a data-squircle attribute on its DOM node. When JavaScript is disabled, the browser applies the noscript CSS, which:

  1. Removes the (non-functional) clip-path
  2. Falls back to standard border-radius using the radius value stored in data-squircle

The result is a rounded element that looks correct even without JavaScript — not a perfect squircle, but a clean, rounded shape that matches the intended cornerRadius.

Setup

Add SquircleNoScript once at the top of your app, typically in your root layout. It only renders inside a <noscript> tag, so it has zero impact on JavaScript-enabled users.

import { SquircleNoScript } from "@squircle-js/react";
export default function RootLayout({ children }) {
return (
<html>
<body>
<SquircleNoScript />
{children}
</body>
</html>
);
}

No other configuration is needed. All Squircle components on the page will automatically benefit from the fallback.

SSR considerations

During server-side rendering, the clip-path style is not yet computed (it requires measuring the element's size in the browser). This means there is a brief window on first paint where the element may appear without the squircle clip-path, particularly for elements where defaultWidth and defaultHeight are not provided.

To minimise this:

  • Provide defaultWidth and defaultHeight when the element size is known, so the clip-path can be computed on the first render pass
  • Use StaticSquircle for elements with fixed dimensions — it computes the path synchronously and can render a stable clip-path from the server
// Server-friendly: clip-path computable immediately
<StaticSquircle
width={48}
height={48}
cornerRadius={12}
cornerSmoothing={0.6}
className="bg-blue-500"
/>
// Also works: defaultWidth/defaultHeight give the component a starting point
<Squircle
defaultWidth={128}
defaultHeight={128}
cornerRadius={20}
cornerSmoothing={0.6}
className="bg-blue-500"
/>

What users see

ScenarioVisual result
JavaScript enabledFull squircle clip-path
JavaScript disabled, SquircleNoScript presentRounded corners via border-radius
JavaScript disabled, no SquircleNoScriptSquare element (no rounding)
SSR, before hydration, with defaultWidth/defaultHeightFull squircle clip-path
SSR, before hydration, without defaultsNo clip-path on first paint