shape(): A New Powerful Drawing Syntax in CSS
shape(): A New Powerful Drawing Syntax in CSS êŽë š
I first saw in the Safari 18.4 release notes that shape()
, a new function is now supported. Then I saw on MDN itâs actually already in Chrome, too!
The shape()
function joins friends like polygon()
, circle()
, rect()
, inset()
, and a handful of others. These functions are used as values for a handful of things in CSS, namely:
clip-path
â Clipping away parts of elementsoffset-path
â Moving elements along a pathshape-outside
â Applied to afloat
-ed element such that content flows along the path
Fair warning:
shape()
only seems to work with clip-path
. I couldnât find a ton of information on this, but the Chrome blog does state it. It will probably work with the other properties in due time.
Letâs focus on clip-path
here which I might argue is the most useful anyway, as it makes an entire element into the shape described which feels like a more generally applicable thing.
I got into this on the CodePen blog where I equated shape()
to <path d="">
in SVG, which is surely the intention. You can actually set the d
attribute in CSS, but it only works on <path>
elements, and the unitless values translate only to pixels, which makes it not particularly CSSy or useful.
One situation I mentioned was Trys Mudfordâs blog post where this was the design situation at hand:

Oh look, a use case.
Those light yellow boxes are basically polygons with rounded corners. In a perfect world, polygon()
could do this with the round
keyword, as specced, but alas that doesnât work just yet. But because shape()
is essentially all-powerful, that does work now (in Chrome and Safari anyway, and this feels like a decently progressive-enhancement thing).
Temani Afif saw that and did the work!
This is very awesome. This is quite the power tool for shape-making. I think weâre going to see a lot of fancy stuff come out of this.
Itâs true we already have a path()
function, but remember, itâs sooooo limited. The values are only pixels, which are some pretty big handcuffs in a responsive world full of intrinsic content (that is, elements on the web that respond to their contents and environment). Simon Fraser on the WebKit blog introduces this new feature and calls it out:
Info
⊠usingÂ
path()
 inÂclip-path
 canât be responsive; you canât write CSS rules so that the path adapts to the size of the element. This is where the newÂshape()
 function comes in.
Coincidentally, Simonâs demo (Jenâs demo?) also shows off an arrow shape:
Thatâs using multiple different drawing commands (line
and arc
, but there are more), keywords like top
and left
(excellent, but I wonder why logical properties donât work?), and, even more deliciously, container units (e.g. cqh
). The orange border there is a good reminder that clip-path
, well, clips. So itâll lop off anything at all on this element in those areas, including content.
Noam Rosenthal got in on the fun over on the Chrome for Developers blog, underscoring just how hard this stuff used to be:
Info
clip-path: shape()
 lets you clip your element using arbitrary and responsive shapes, previously only possible using techniques like conic gradients or JavaScript-constructed SVG.
And like all this good company, absolutely couldnât resist peppering in other CSS goodness into a demo. His demo here uses different drawing commands than weâve seen so far, custom properties (which are an extremely natural fit), and even animation (!!).
I see Temani is hard on the case with a blob generator using shape()
, which, I believe as long as there are the âsame number of pointsâ, can be animated by changing the clip-path
entirely. Like:
And obviously I love this:
The Actual Shape Commands
The spec covers them, but the best writeup Iâve seen is Geoffâs on CSS-Tricks. Heâs got a bit more detail so check that out, but hereâs the list:
line
vline
hline
arc
curve
smooth
Each of them have a bit of sub-syntax to themselves. Like the curve
command might look like curve to 50% 50% with 50% 0
which would continue drawing the shape to the exact center of the element in a curve in which the top center is a âcontrol pointâ and so curves in that direction.
In my experience itâs quite easy to make a small mistake in the syntax and wreck the whole thing. But hey thatâs understandable.
Squircles with shape()
I get to have some fun too! It occurred to me that digital designs most elusive beast, the squircle, might be now achievable with reasonable normal web tech.
SVG can do it, but I wouldnât call it particularly readable code. âMonoco is a tiny JavaScript library that adds squirclesâ (via SVG background images) and it does a pretty good job of it Iâd say, but thatâs more technology than I normally like to throw at something like this. Jared White by way of Simeon Griggs has a pretty nice SVG-based solution as well, leveraging SVG-as-clip-path.
I like how relatively chill that SVG path
is, but still, shape()
can allow us to squish this down into just CSS which is kinda sweet.
That is⊠if I was fully smart enough to do it.
I crudely drew one in Figma so that I could label the points for writing the syntax out.

I figured if I just did a curve
to every one of those points with control points a bit the edges, it would⊠work? So basically like this:
div {
clip-path: shape(
from 5% 3%,
curve to 95% 3% with 50% 0,
curve to 97% 5% with 97% 3%,
curve to 97% 95% with 100% 50%,
curve to 95% 97% with 97% 97%,
curve to 5% 97% with 50% 100%,
curve to 3% 95% with 3% 97%,
curve to 3% 5% with 0% 50%,
curve to 5% 3% with 3% 3%,
);
}
Which basically works (chriscoyier
). I tried playing around with arc
and smooth
instead but couldnât manage to make it any better (with my like zero geometry skills). Then instead of hard coding those percentage values, I made them in custom properties with sliders to squiggle them around a little.
Itâs a little janky â but I trust someone make like a real quality geometrically sound version eventually.
Update #1
I heard from Peter Herbert over email:
Info
I found a somewhat more accurate version of the iOS squircle. Apparently the Apple squircle uses three cubic beziers in each corner. The original research that figured out the curves I found here, and I used Claude to find the points.
Update #2
Matthew Morete commented below with a tool he made that converts SVG path commands into shape()
commands, which is awesome. Squircles are one of the provided demos, and the commands are very chill:
.squircle {
clip-path: shape(
from 0% 50%,
curve by 50% -50% with 0% -45% / 5% -50%,
smooth by 50% 50% with 50% 5%,
smooth by -50% 50% with -5% 50%,
smooth by -50% -50% with -50% -5%
);
}