COMPONENT / blueprint-grid
Blueprint Grid_
Drafting-paper background: 24px minor and 120px major --label grid lines with optional --ink crosshairs at the major intersections. Static, pure CSS. Requires @cybr/tokens.
Install
1. Map the
@cybrnamespace, once per project. Add this inside yourcomponents.json, or into its existing"registries"object. Nocomponents.jsonyet? Runnpx shadcn@latest initfirst to create one."registries": { "@cybr": "https://cybr-ui.com/r/{name}.json" }2. Add components:
$ npx shadcn@latest add @cybr/blueprint-grid
If shadcn reports Unknown registry "@cybr", step 1 is missing from that project's components.json.
Preview
01 / BLUEPRINT GRID
24PX MINOR · 120PX MAJOR · CROSSHAIRS
registry/ui/blueprint-grid.tsx
import type { ComponentProps, CSSProperties } from "react";
import { cn } from "@/lib/utils";
const CROSS = 12;
// Drafting-paper background: a minor grid inside a major grid, both in --label,
// with optional --ink crosshairs where the major lines meet. The pattern sits
// in an aria-hidden layer behind the children, so layout classes on the root
// apply to the children directly. Static, so there is nothing to reduce.
export function BlueprintGrid({
minor = 24,
major = 120,
crosshairs = true,
className,
children,
...props
}: ComponentProps<"div"> & {
minor?: number;
major?: number;
crosshairs?: boolean;
}) {
const strong = "color-mix(in srgb, var(--label) 35%, transparent)";
const faint = "color-mix(in srgb, var(--label) 12%, transparent)";
const line = (color: string, to: string) =>
`linear-gradient(${to}, ${color} var(--border-hair), transparent var(--border-hair))`;
const grid: CSSProperties = {
backgroundImage: [
line(strong, "to bottom"),
line(strong, "to right"),
line(faint, "to bottom"),
line(faint, "to right"),
].join(", "),
backgroundSize: `${major}px ${major}px, ${major}px ${major}px, ${minor}px ${minor}px, ${minor}px ${minor}px`,
};
// Major lines in --ink, masked down to a small square around each intersection.
const cross: CSSProperties = {
backgroundImage: `${line("var(--ink)", "to bottom")}, ${line("var(--ink)", "to right")}`,
backgroundSize: `${major}px ${major}px`,
maskImage: `linear-gradient(to right, black ${CROSS}px, transparent ${CROSS}px), linear-gradient(to bottom, black ${CROSS}px, transparent ${CROSS}px)`,
maskSize: `${major}px ${major}px`,
maskPosition: `${-CROSS / 2}px ${-CROSS / 2}px`,
maskComposite: "intersect",
};
return (
<div className={cn("relative isolate overflow-hidden bg-ground-deep", className)} {...props}>
<div aria-hidden="true" className="pointer-events-none absolute inset-0 -z-10" style={grid}>
{crosshairs ? <div className="absolute inset-0" style={cross} /> : null}
</div>
{children}
</div>
);
}
Repo source. The shadcn CLI rewrites import aliases to match your project.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| minor | number | 24 | Minor grid spacing in px. Faint --label lines (12%). |
| major | number | 120 | Major grid spacing in px. Stronger --label lines (35%). |
| crosshairs | boolean | true | Draw small --ink + marks where the major lines meet. |
| ...props | ComponentProps<"div"> | — | Every other native <div> attribute is forwarded; className is merged last with cn(). Give the root a height (or content) and any layout classes; they apply to the children directly. |
Usage
Needs the stylesheet from @cybr/tokens. After the install, import it in app/globals.css:
@import "tailwindcss";
@import "../styles/cybr-tokens.css";
import { BlueprintGrid } from "@/components/ui/blueprint-grid";
export function Hero() {
return (
<BlueprintGrid className="flex min-h-96 items-center justify-center">
<h1 className="font-display text-display-lg text-ink uppercase">Drafted</h1>
</BlueprintGrid>
);
}
States
- Default: minor and major grids on
--ground-deep, with crosshairs on the major intersections. - No crosshairs:
crosshairs={false}leaves just the two grids. - Reduced motion: nothing animates, so there is no change.
- The artboard's navy ground maps to
--ground-deep; colours follow the tokens, not the mockup.
Accessibility
- The grid is one
aria-hiddenlayer behind the children and never takes pointer events. - Grid lines are faint
--labelmixes, so text on top keeps the contrast of--ground-deep. Use--inkor--labelfor text.