Demos

Each example is a live <pattern-grid> element styled with author CSS. View source on this page to see exactly how each one is built.

1. Hello rainbow

A 64-cell grid with HSL hues driven by sibling-index() and sibling-count().

<pattern-grid cells="8x8"></pattern-grid> <style> pattern-grid { display: grid; grid-template-columns: repeat(var(--pg-cols), 1fr); } pattern-grid > i { aspect-ratio: 1; background: hsl( calc(sibling-index() / sibling-count() * 360) 70% 50% ); } </style>

2. Concentric rotation

32 cells stacked in the same grid cell, each smaller and more rotated than the last. No JS animation โ€” pure CSS.

<pattern-grid cells="32"></pattern-grid> <style> pattern-grid { display: grid; place-items: center; aspect-ratio: 1; } pattern-grid > i { grid-area: 1 / 1; width: calc(100% * sibling-index() / sibling-count()); aspect-ratio: 1; border: 1px solid hsl(calc(sibling-index() * 11) 70% 60%); border-radius: 30%; transform: rotate(calc(sibling-index() * 5deg)); } </style>

3. 2D coordinates from the sibling shim

With shim="sibling", the component sets typed integer custom properties (--i per cell, --n on the host). That lets mod() and floor() recover (x, y) coordinates reliably. Color shifts on a diagonal.

<pattern-grid cells="16x16" shim="sibling"></pattern-grid> <style> /* Register so CSS math types numerically */ @property --idx { syntax: '<integer>'; inherits: false; initial-value: 0; } @property --x { syntax: '<integer>'; inherits: false; initial-value: 0; } @property --y { syntax: '<integer>'; inherits: false; initial-value: 0; } pattern-grid > i { --idx: calc(var(--i) - 1); --x: mod(var(--idx), var(--pg-cols)); --y: calc((var(--idx) - var(--x)) / var(--pg-cols)); background: hsl( calc((var(--x) + var(--y)) * 8) 70% 50% ); } </style>

4. Template cells

Provide a <template> child and each cell becomes a clone of its content. Buttons here, but it can be anything โ€” links, images, custom elements.

<pattern-grid cells="4x4"> <template> <button class="tile">+</button> </template> </pattern-grid>

5. Hand-authored cells (no JS required)

When the child count already matches cols ร— rows, JS leaves them alone. This block also renders correctly with JavaScript disabled.

<pattern-grid cols="3" rows="2"> <a href="#one"></a> <a href="#two"></a> <a href="#three"></a> <a href="#four"></a> <a href="#five"></a> <a href="#six"></a> </pattern-grid>

6. Vanilla Breeze tokens

Because cells live in the light DOM, any inherited custom properties cascade in. Here the design tokens come from a parent.

/* VB tokens cascade into light DOM cells */ pattern-grid > i { background: hsl( calc(sibling-index() / sibling-count() * 360) var(--vb-color-saturation) var(--vb-color-lightness) ); border-radius: var(--vb-radius-sm); }

7. Sibling shim โ€” works in Firefox today

Setting shim="sibling" writes --i on each cell and --n on the host, so author CSS works in browsers that don't yet ship sibling-index(). Author CSS can prefer the native function with a fallback.

With shim="sibling":

Without shim:

<pattern-grid cells="36" shim="sibling"></pattern-grid> <style> pattern-grid > i { /* prefer shim, fall back to native */ --idx: var(--i, sibling-index()); background: hsl(calc(var(--idx) * 10) 70% 50%); } </style>

8. Seeded randomness

Wrap a <pattern-grid> in <seed-context> and the component writes --rand-0...--rand-7 floats and matching --randi-0...--randi-7 integers on each cell, derived from a seeded mulberry32 PRNG. Same seed reproduces the same randoms across reloads.

<seed-context seed="hello"> <pattern-grid cells="8x8"></pattern-grid> </seed-context> <style> pattern-grid > i { background: hsl( calc(var(--rand-0) * 360deg) 70% 50% ); } </style>

9. API explorer

Drag the sliders to mutate cols and rows attributes live. The component listens to attribute changes and regenerates cells.

10. The render event

Every regeneration fires a pattern-grid:render event with the new { cols, rows, total } in its detail. Useful for tying side effects to grid changes.

document.querySelector('pattern-grid') .addEventListener('pattern-grid:render', (e) => { console.log('Regenerated:', e.detail); // e.detail === { cols: 8, rows: 8, total: 64 } });