ComponentSite and product
Dot icon
Static SVG icon defined by rows of dots and rings.
$ npx context-ds add dot-glyphUsage
Use it for
Plan marks, card glyphs, empty states.
Avoid
- Dot icons as body illustrations
- Moving or melting dots (use a glyph tile or glyph melt)
Example
examples/dot-glyph.tsx
import { DotGlyph } from "@/components/ui/dot-glyph";// 2 is a solid dot, 1 a ring, anything else an empty cell.const GEM = ["..2..", ".222.", "22222", ".222.", "..2.."];const SEARCH = ["222..", "2.2..", "222..", "...2.", "....2"];const PAGE = ["2222.", "2..22", "2...2", "2...2", "22222"];const CHECK = ["1111111", "1111112", "1111122", "2111221", "2212211", "1222111", "1121111"];// The dot icon is a static SVG icon: small, inline with text, in the text's color.export function Product() { return ( <div className="flex flex-col items-start gap-5"> <span className="flex items-center gap-1.5 text-body-sm text-fg"> <DotGlyph rows={GEM} className="size-4 text-brand" /> 4,820 credits </span> <div className="flex flex-wrap items-center gap-4 text-body-sm text-fg-muted"> <span className="flex items-center gap-1.5"> <DotGlyph rows={PAGE} className="size-3 text-brand" /> Scrape </span> <span className="flex items-center gap-1.5"> <DotGlyph rows={SEARCH} className="size-3 text-fg/55" /> Search </span> </div> </div> );}export function Site() { return ( <div className="flex items-center gap-4"> <DotGlyph rows={CHECK} className="size-12 text-fg-brand" /> <p className="text-body text-fg">SOC 2 Type II</p> </div> );}Source
components/ui/dot-glyph.tsx
import type { CSSProperties, ReactNode } from "react";export const GLYPH_PITCH = 3.2;export const GLYPH_DOT_RADIUS = 1.25;const GLYPH_RING_STROKE = 0.55;/** * An icon drawn on a small square grid of dots, the brand's dot language. Each row is a string: 2 is a solid dot, * 1 a hollow ring, anything else an empty cell. Each dot carries --dot-delay, growing along the diagonal from the top * left, for animations that sweep across the glyph. Children draw on the same grid, above the dots. */export function DotGlyph({ rows, className, dotStaggerMs = 0, children }: { rows: readonly string[]; className?: string; dotStaggerMs?: number; children?: ReactNode }) { const size = rows.length * GLYPH_PITCH; return ( <svg aria-hidden="true" viewBox={`0 0 ${size} ${size}`} data-slot="dot-glyph" className={className}> {rows.flatMap((row, y) => [...row].map((cell, x) => { if (cell !== "1" && cell !== "2") return null; const solid = cell === "2"; return ( <circle key={`${x}:${y}`} cx={(x + 0.5) * GLYPH_PITCH} cy={(y + 0.5) * GLYPH_PITCH} r={solid ? GLYPH_DOT_RADIUS : GLYPH_DOT_RADIUS - GLYPH_RING_STROKE / 2} fill={solid ? "currentColor" : "none"} stroke={solid ? "none" : "currentColor"} strokeWidth={GLYPH_RING_STROKE} style={{ "--dot-delay": `${(x + y) * dotStaggerMs}ms` } as CSSProperties} /> ); }), )} {children} </svg> );}Reference: context-dashboard c0ddf7a src/components/ui/dot-glyph.tsx.