How to background patterns in ui design systems: svg strategy
- Step 1Decide where patterns are allowed — Write the rule into your guidelines: patterns belong on decorative surfaces (heroes, empty states, sign-in panels, card headers) and never behind primary reading content or data tables. Density and contrast must keep text WCAG-legible.
- Step 2Choose one motif and keep it simple — A design system reads best with one or two motifs used consistently. Simple shapes (dot, plus, hairline) tile cleanly at small sizes and survive recolouring. Prepare the motif as a single SVG before tiling.
- Step 3Recolour the motif to your token palette first — The tiler does not recolour. Map the motif to your brand colours up front with svg-hex-swapper, or to
currentColor/ nearest Tailwind colours with svg-to-tailwind so the pattern inherits text colour for theming. - Step 4Tile it at your defined densities — Run the motif through the tiler at the two or three densities your system needs (e.g. subtle = large tile + spacing, bold = small tile). Keep rotation and background consistent per token so variants stay coherent.
- Step 5Name and store the surface tokens — Save each output under a token name (
surface/pattern/subtle,surface/pattern/bold,surface/pattern/inverse). Store the SVGs in your asset repo and reference them by token, not by raw file, so swaps are centralised. - Step 6Bring it into Figma and components — Paste the generated SVG into a Figma frame (it tiles via its own
<pattern>), or wire it into components as inline SVG or a CSS background via svg-css-data-uri. Document allowed usage next to the token.
When a background pattern helps vs hurts
A usage matrix for design-system guidelines. The rule of thumb: patterns belong on decorative surfaces, never behind dense reading content.
| Surface | Pattern? | Why |
|---|---|---|
| Marketing hero / landing section | Yes | Decorative; no fine print competing for attention |
| Empty state / zero-data view | Yes | Fills dead space, adds personality without harming content |
| Sign-in / auth panel | Yes (subtle) | Branding moment; keep contrast low behind the form |
| Card header strip | Yes (subtle) | Defines the card without overpowering its content |
| Behind body paragraphs | No | Reduces text contrast and legibility |
| Behind data tables / dashboards | No | Competes with dense data; raises cognitive load |
Who owns each step of the pattern pipeline
The pattern tiler builds the tiling. Recolour, theming, and delivery are separate steps handled upstream or downstream.
| Step | Owner | Tool / action |
|---|---|---|
| Create / choose the motif | Design | Your icon set or a generated shape (blob / poly / wave) |
| Recolour to brand tokens | Upstream | svg-hex-swapper |
| Make it theme-aware (currentColor) | Upstream | svg-to-tailwind (current mode) or css-variable-injector |
| Tile into a seamless pattern | This tool | Set tileSize, spacing, rotation, background; export SVG |
| Deliver as CSS background | Downstream | svg-css-data-uri |
| Trim asset weight | Downstream | svg-pro-minifier |
Cookbook
Concrete recipes for building a coherent set of pattern surfaces in a design system. Each names the token and the settings that produce it.
Two-density surface tokens from one motif
A subtle and a bold variant of the same motif gives designers a choice without fragmenting the system. Same motif, different tile size.
Motif: brand-dot.svg (already recoloured to --surface-fg) surface/pattern/subtle: Tile size 90, Spacing 30, Rotation 0 surface/pattern/bold: Tile size 40, Spacing 12, Rotation 0 -> two <pattern> SVGs, identical structure, different cell size
Theme-aware pattern via currentColor
Map the motif to currentColor before tiling so the same pattern adapts to light/dark by inheriting the surface text colour.
1. svg-to-tailwind (current mode) on the motif
-> fill becomes currentColor
2. Tile it: Tile size 60, Spacing 16, Background transparent
3. In CSS, set color on the container:
.surface-dark { color: rgba(255,255,255,.06) }
.surface-light { color: rgba(15,23,42,.05) }
# One pattern, both themes, no second assetInverse (dark) surface token with a solid background
For a self-contained dark surface, give the tiler an opaque background colour so the token doesn't depend on what's behind it.
surface/pattern/inverse: Tile size 50, Spacing 14, Background #0f172a Generated cell background: <rect width="64" height="64" fill="#0f172a"/> # The motif sits on top; token is drop-in on any page.
Figma handoff
Designers and engineers share one source: the generated SVG. Paste it into Figma; it tiles via its own <pattern>.
1. Generate the pattern SVG in the tiler. 2. In Figma: paste the SVG onto a frame (Edit > Paste). It renders as a vector that tiles via <pattern>. 3. Name the layer to the token (surface/pattern/subtle). 4. Engineers use the same exported SVG file -> no drift.
Keep tokens diffable in the asset repo
Because the tiler's output is deterministic, regenerating a token only changes the file when its inputs change — clean diffs in review.
tokens/patterns/ surface-pattern-subtle.svg surface-pattern-bold.svg surface-pattern-inverse.svg # Regenerate from a build script; git diff is empty unless # the motif or settings actually changed.
Edge cases and what actually happens
Pattern placed behind body text
AvoidEven a subtle pattern lowers effective text contrast. Keep patterns off reading surfaces, or drop opacity so the AA contrast ratio of the text above is preserved. This is a guideline, not something the tool enforces.
Expecting the tiler to recolour for your palette
Not supportedThe only colour control is the background. Recolour the motif first with svg-hex-swapper; the tiler tiles whatever colours the motif already has.
Expecting automatic light/dark theming
Not supportedThere is no theme toggle. Achieve theming by mapping the motif to currentColor via svg-to-tailwind before tiling, then set color per theme on the container.
Motif too detailed at small tile sizes
Watch outComplex motifs turn to mush below ~40px tiles. Use a simpler motif for dense tokens; reserve detail for large, sparse surfaces.
Inconsistent rotation across variants
Watch outMixing rotations within one token family looks accidental. Decide one rotation per token and keep it fixed; treat rotation as a deliberate design choice, not a per-export whim.
Duplicate pattern ids when composing tokens on one page
Watch outThe pattern id is tile-<stem>. If two tokens come from same-named source files and are inlined together, ids collide. Rename sources or edit ids before embedding.
Transparent token relying on page background
By designA transparent-background token shows whatever is beneath it. That's intended for overlay tokens; use an opaque background for a self-contained surface token.
Shipping a tiled PNG instead of SVG
AvoidRaster textures need a 1x/2x/3x export matrix and blur on odd DPIs. The SVG <pattern> stays crisp everywhere and is smaller — prefer it for system tokens.
Unminified pattern bloating the bundle
Watch outEditor cruft in the motif carries into every tile usage. Run the motif (or the final pattern) through svg-pro-minifier before tokenising.
Frequently asked questions
Where should background patterns be used in a design system?
On decorative surfaces — heroes, empty states, auth panels, card headers — and never behind body text or data tables. Encode that rule in your guidelines so usage stays consistent.
Does the tiler recolour the motif to my brand?
No. Recolour the motif first with svg-hex-swapper or map it to your palette with svg-to-tailwind, then tile the recoloured file. The tiler's only colour control is the background.
How do I make a pattern theme-aware (light/dark)?
Map the motif to currentColor (via the Tailwind tool's current mode or the CSS variable injector) before tiling, then set color on the container per theme. One pattern serves both modes.
How should I name pattern tokens?
Use a surface namespace with an intensity suffix, e.g. surface/pattern/subtle, surface/pattern/bold, surface/pattern/inverse. Reference tokens, not raw files, so swaps are centralised.
Will it work in Figma?
Yes — paste the generated SVG into a Figma frame; it tiles via its own <pattern>. Engineers use the same exported file, so design and code share one source.
How many densities should I ship?
Two or three from a single motif (subtle / bold, optionally inverse) is plenty. More variants fragment the system. Keep the motif and rotation consistent across them.
Why SVG instead of a PNG texture?
SVG <pattern> stays crisp at every DPI, recolours by editing markup, and is far smaller than a raster export matrix. PNG textures blur and bloat.
Can the tiler create the motif for me?
No — it tiles a motif you provide. For generated motifs, build one with the blob generator, low-poly generator, or wave divider, then tile it.
How do I keep pattern surfaces legible?
Lower the pattern's opacity and keep it off reading surfaces. The tool won't check contrast for you — bake legibility into your guidelines and verify text contrast above the pattern.
How do I deliver the pattern in components?
Inline the SVG, or convert it to a CSS background-image with svg-css-data-uri. Inline lets you restyle/animate; the data URI is one CSS line.
How do I keep the asset light?
Use a simple motif and run it (or the final pattern) through svg-pro-minifier to strip editor cruft. A clean motif keeps every tile usage small.
Are regenerated tokens diffable?
Yes — output is deterministic, so a token's SVG only changes when its motif or settings change. That keeps design-system asset PRs clean and reviewable.
Privacy first
Every JAD SVG tool runs entirely in your browser using the DOM API and Canvas. Your SVG files never leave your device — verified by zero outbound network requests during processing.