Corner Shape Grid
A 4 × 3 grid of 73 px cells whose cut depends on their place (superellipses at the corners, bevels along the top and bottom, scoops on the sides, notches in the middle), where a click draws a random shape for the cell among seven clip-path: polygon(): a plan you read by shape.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Glassmorphism has 47 effects, including 6 free. Explore the category →
3 usage examples



How it works
The .cs-grid-wrap grid (4 columns, gap: 8px, 12 px padding, 340 px at most) lines up twelve square .cs-grid-item cells (aspect-ratio: 1, 73 × 73 px measured), each with its gradient and its number in white 13.6 px. Each cell carries seven shape variables in percentages: --csg-squircle (superellipse n = 4), --csg-squircle-tight (n = 5) and --csg-squircle-soft (n = 3), 64 points each; --csg-bevel (22% bevel) and --csg-bevel-sm (12%); --csg-notch (16% square notch); --csg-scoop-concave (22% quarter-circle scoop). :nth-child rules set the shape by place: corners 1 and 12 as n = 4, corners 4 and 9 as n = 5, top and bottom edges (2, 3, 10, 11) as a small bevel, sides (5, 8) as scoops, middle (6, 7) as notches.
The JavaScript (a 0.5 KB IIFE) listens for clicks on #cs-grid and, on the clicked cell, writes style.clipPath = 'var(--csg-…)' with one of the seven shapes drawn at random — measured in Chromium 151, Firefox 153 and WebKit 26: the inline variable resolves to a polygon() and the cell changes its cut. One chance in seven of drawing the same shape again: the click then seems to do nothing. On hover the cell grows 10% and brightens 20% over 0.4 s, raised above its neighbors (z-index: 2). Under 480 px wide, the grid switches to three columns and 260 px.
The seven shapes are CSS variables set on each cell (--csg-notch, --csg-bevel…), and the JavaScript array holds their names ('var(--csg-notch)'…) rather than url(#…) pointing to SVG <clipPath>s. That way the click writes a shape that always exists: a url() to an SVG missing from the page would leave all twelve cells square and the click without effect. The code stays in a single block, with no SVG and no id to supply.
Accessibility
- Click only: the cells are
divs with no role and notabindex, the listener only reacts to clicks — neither Tab nor Enter reaches the grid (measured). For a booking grid, make each cell a<button>: a keyboard click fires the same event, and the script'sclosest('.cs-grid-item')still works.clip-pathclips the focus ring: mark it withfilter: brightness(1.3)on:focus-visible. - Shape says nothing on its own: a screen reader does not see that a cell is a corner or a middle, nor that it just changed. Write the place and status in the text or an
aria-label(“Stand 4, corner, free”), and announce the change (aria-pressed, or anaria-liveregion). - Contrast and motion: white 13.6 px digits at 4.47:1 on
#6366f1(just under the 4.5:1 threshold) and 5.7:1 on#7c3aed, but 2.4:1 on#06b6d4, 2.5:1 on#14b8a6and#10b981; the two amber cells, with dark text, pass (7.9:1 and 5.3:1). Noprefers-reduced-motion: the 10% hover grow stays active (measured).
Browser compatibility
CSS: grid, aspect-ratio, clip-path: polygon() in percentages, custom properties, :nth-child, a media query at 480 px. JavaScript: a dependency-free IIFE, one click listener. Zero SVG. Shapes and click change measured in Chromium 151, Firefox 153 and WebKit 26.
The minimum versions come from aspect-ratio (Chrome 88, Firefox 89, Safari 15): before that, cells lose their own height and collapse onto their text; add height: 73px as a fallback. Without clip-path, cells stay square and the click changes nothing visible.
The code
HTML structure to paste into your page (the CSS + JS come with Premium):
<div class="demo-preview">
<div class="cs-grid-wrap" id="cs-grid">
<div class="cs-grid-item">1</div>
<div class="cs-grid-item">2</div>
…
<div class="cs-grid-item">12</div>
</div>
</div>
The full HTML + CSS + JS of Corner Shape Grid, ready to paste — plus all 840 effects. Or $299 once, lifetime access.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Shape by place (CSS — .cs-grid-item:nth-child(n) rules) |
superellipse corners, 12% bevel on top and bottom edges, scoops on the sides, notches in the middle | Each rule calls a variable: clip-path: var(--csg-bevel) for a large bevel. All seven shapes are available on every cell. |
Shapes drawn on click (JS — array r) |
all seven variables | Remove names to narrow the draw, or replace chance with a cycle: t.dataset.i = (+(t.dataset.i || 0) + 1) % r.length; t.style.clipPath = r[t.dataset.i]. |
Columns (CSS — grid-template-columns and the 480 px media query) |
4 columns, 3 under 480 px | Shapes are set by number, not by actual position: if you change the column count, rewrite the :nth-child rules to get corners, edges and middle back. |
Shape depth (CSS — --csg-* variables on .cs-grid-item) |
bevels 22 and 12%, notch 16%, scoop 22% | For a b% bevel, the eight points are 0 b%, b% 0, (100−b)% 0, 100% b%…. Beyond 25%, the straight sides become shorter than the cuts; at 50%, the cuts meet in the middle of the sides. |
Hover (CSS — .cs-grid-item:hover) |
scale(1.1), brightness(1.2), z-index: 2 |
scale(1.05) for a tight grid where the grow covers the neighbors. |
FAQ
clip-path transition is set, and the seven shapes do not share a point count: 64 for the superellipses, 8 for the bevels, 12 for the notch, 28 for the scoop. The browser only interpolates polygons with the same number of points; adding transition: clip-path .4s would only animate changes from one superellipse to another, or from one bevel to the other (8 points each). For a morph between all shapes they must be redrawn with the same structure — which is what Morphing Corner Shapes (fx-0337) does: four 68-point shapes that move from one to another with an animated transition on hover.document.getElementById('cs-grid'), hence the first grid only, and two elements cannot share an id. Replace the first line with a loop: document.querySelectorAll('.cs-grid-wrap').forEach(function (e) { e.addEventListener('click', …) }) — which is what this page's scene file does for its three grids. The shapes, in CSS, have no such problem.:nth-child rules for three columns inside the media query (corners 1, 3, 10, 12).