Grid Pattern

A decorative SVG line grid that fills its positioned parent, with optional accent cells (`squares`, addressed as `[column, row]`) that can pulse. Colour comes from `currentColor`, so a text-colour class on `className` sets the tone.

decorativeclientuiv1.2.0

Preview

Grid Pattern — live renderblocks-gridpattern--default

Rendered from the story the storybook (a11y) CI gate runs axe against — the preview can't show something that hasn't been verified.

Install

Two equivalent paths — the URL works in any shadcn-CLI setup; the alias works once you've registered @interlace in your components.json.

Via shadcn URL
npx shadcn@latest add https://ds.interlace.tools/r/grid-pattern.json
With the @interlace alias
npx shadcn@latest add @interlace/grid-pattern

History

This component is at v1.2.0, first shipped in @interlace/ui 1.0.0. The version is stamped as a banner into the file the install writes, so the copy in your tree says which one you have — compare it with the number above before deciding whether to re-run the install.

No release note names this component yet. It shipped with the release above and has not changed since — see the full changelog for what moved elsewhere in the DS.

Import

2 named exports — pull the parts you need.

Public API
import { GridPattern, GridPatternSquare } from '@/components/ui/patterns/grid-pattern';

Anatomy

Extracted from the primitive's JSDoc header. The source is the only documentation that can't drift.

GridPattern                      (svg — data-slot="grid-pattern")
    ├─ defs > pattern              (one cell: `M.5 {h}V.5H{w}`, id from useId)
    ├─ rect 100%×100%              (fills the parent with the tiled pattern)
    └─ svg                         (data-slot="grid-pattern-squares")
        └─ rect | motion.rect      (data-slot="grid-pattern-square")

API reference

Parsed from the type declarations in the source — the same file the install writes into your tree, so this table can't drift from the component you get.

GridPatternProps

PropTypeDescription
cellWidthnumberWidth of a single grid cell, in user-space units. @default 40
cellHeightnumberHeight of a single grid cell, in user-space units. @default 40
offsetXnumberHorizontal offset of the pattern origin, in user-space units. A small negative value (the default) clips the leading edge so the grid bleeds cleanly past the left edge of its container. @default -1
offsetYnumberVertical offset of the pattern origin, in user-space units. @default -1
strokeWidthnumberStroke width of the grid lines, in user-space units. @default 1
dashArraystringSVG `stroke-dasharray` for the grid lines. `"0"` draws solid lines; e.g. `"4 2"` draws a dashed grid. @default "0"
squaresGridPatternSquare[]Cells to fill as accents, each `[column, row]`. Filled cells inherit the SVG's `fill`/`fill-opacity` (`currentColor` by default — set via a text color utility on `className`). @default undefined
animatedbooleanPulse the accent `squares` with a soft opacity loop. Automatically forced off when the user prefers reduced motion. Has no effect unless `squares` is provided. @default false
animationDurationnumberSeconds for one full pulse cycle of an animated accent cell. @default 4

Accessibility

Every story for this component is rendered headlessly and checked with axe-core (wcag2aa, wcag22aa, best-practice, ACT) on every PR. That gate has no continue-on-error, so what ships has zero known violations.

What follows is what static analysis can see. Axe cannot press a key and never sees an overlay open, so the operable-without-a-mouse claim lives in Behavior instead, where the keyboard path is replayed step by step.

Focus + keyboard behaviour
Native element semantics — no interaction layer to get wrong.
Focus ring (WCAG 2.2 SC 2.4.13)
Not focusable — no focus indicator required.
Reduced motion
Animation is gated on prefers-reduced-motion.
ARIA in the source
  • aria-hidden

Examples

3 more states from the same story file.

R-rule compliance

Every primitive in @interlace/ui models to the portable 26-rule floor enforced by the componentApi ESLint preset. The cells below pin exactly where each rule applies in this file.

RuleConceptWhere
R4Extends native el`ComponentPropsWithoutRef<'svg'>` + `forwardRef`
R5testid required, no default`'data-testid': string`
R6data-slot per part`grid-pattern` / `-squares` / `-square`
R7className merged + ...rest`cn(BASE, className)` + `{...props}`
R8No `isXxx``animated`, `squares`, `dashArray`
R19Tokens only`fill-current` / `stroke-current`; no colour prop
R25Client component`useId` + `useReducedMotion`
R26A11y`aria-hidden="true"` — decorative, never in the tree

Dependencies

Base UI primitive
Native / no Base UI dependency
Lucide icons
none
NPM dependencies
  • motion

Source

The full implementation — components/ui/patterns/grid-pattern.tsx once installed.

261 lines · TypeScript
"use client";

import { ComponentPropsWithoutRef, forwardRef, useId } from "react";

// @interlace/grid-pattern v1.2.0 — Interlace design system.
// Docs, props and live preview: https://ds.interlace.tools/c/grid-pattern
// What changed since: https://ds.interlace.tools/c/grid-pattern#history
// Generated banner — keep it, the upgrade diff reads this version.

/**
 * @interlace/ui — GridPattern
 *
 * A decorative SVG line grid that fills its positioned parent, with optional
 * accent cells (`squares`, addressed as `[column, row]`) that can pulse.
 * Colour comes from `currentColor`, so a text-colour class on `className` sets
 * the tone.
 *
 * The whole surface is `aria-hidden` and `pointer-events-none`.
 *
 * ## Anatomy

…241 more lines…

Registry JSON

The raw registry record — what the shadcn CLI fetches.