Brutalist Grid
Off-white paper bg with thick 2px black borders, JetBrains Mono labels, asymmetric tile grid (avatar + name + bio), 2-column link grid with rotated number labels, and oversized featured-product tiles.
Preview
Source
tsx
"use client";
import {
Instagram,
Twitter,
Youtube,
Mail,
Globe,
ShoppingBag,
PlayCircle,
Linkedin,
Music2,
ArrowUpRight,
type LucideIcon,
} from "lucide-react";
import type { LinkIcon, LinksInBioData, RichBlock } from "../types";
import { defaultData } from "../defaultData";
const ICONS: Record<LinkIcon, LucideIcon> = {
instagram: Instagram,
twitter: Twitter,
tiktok: Music2,
youtube: Youtube,
spotify: Music2,
apple: Music2,
linkedin: Linkedin,
email: Mail,
globe: Globe,
shop: ShoppingBag,
play: PlayCircle,
};
const PAPER = "#f3f0e8";
const INK = "#0c0c0c";
const ACCENT = "#ff5b1f";
function pad(n: number) {
return String(n).padStart(2, "0");
}
export interface LinksInBioBrutalistGridProps {
data?: LinksInBioData;
}
export default function LinksInBioBrutalistGrid({
data = defaultData,
}: LinksInBioBrutalistGridProps) {
const products =
data.richBlocks?.filter(
(b): b is Extract<RichBlock, { kind: "featured-product" }> =>
b.kind === "featured-product"
) ?? [];
return (
<>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Space+Grotesk:wght@400;500;700&display=swap"
/>
<section
className="min-h-screen w-full px-4 py-12 sm:px-6 sm:py-16"
style={{
background: PAPER,
color: INK,
fontFamily: "'JetBrains Mono', monospace",
}}
>
<div className="mx-auto w-full max-w-[680px]">
<div className="mb-4 flex items-center justify-between text-[10px] uppercase tracking-[0.25em]">
<span>// links.bio</span>
<span>v1 · {new Date().getFullYear()}</span>
</div>
<div
className="grid gap-2 border-2"
style={{ gridTemplateColumns: "repeat(6, 1fr)", borderColor: INK }}
>
{/* AVATAR TILE — spans 2 cols */}
<div
className="col-span-2 row-span-2 border-r-2 border-b-2 p-3"
style={{ borderColor: INK }}
>
<div className="aspect-square overflow-hidden border-2" style={{ borderColor: INK }}>
<img
src={data.avatar}
alt={data.name}
width={400}
height={400}
loading="eager"
className="h-full w-full object-cover"
style={{ filter: "grayscale(0.15) contrast(1.05)" }}
/>
</div>
<p className="mt-2 text-[10px] uppercase tracking-[0.2em]">[ portrait ]</p>
</div>
{/* NAME TILE — spans 4 cols */}
<div
className="col-span-4 border-b-2 p-5"
style={{ borderColor: INK, background: ACCENT, color: INK }}
>
<p className="text-[10px] uppercase tracking-[0.25em]">// identity</p>
<h1
className="mt-2 leading-[0.95] tracking-tight"
style={{
fontFamily: "'Space Grotesk', sans-serif",
fontWeight: 700,
fontSize: "clamp(1.6rem, 4.6vw, 2.5rem)",
}}
>
{data.name}
{data.verified && <span className="ml-2 align-top text-base">[✓]</span>}
</h1>
{data.handle && (
<p className="mt-1 text-sm font-medium">{data.handle}</p>
)}
</div>
{/* BIO TILE — spans 4 cols */}
<div className="col-span-4 border-b-2 p-5" style={{ borderColor: INK }}>
<p className="text-[10px] uppercase tracking-[0.25em] opacity-60">// bio</p>
<p className="mt-2 text-[15px] leading-snug">{data.bio}</p>
</div>
{/* LINKS — 2-column grid with selective spanning */}
{data.links.map((link, i) => {
const span = i % 5 === 0 ? "col-span-6" : "col-span-3";
const Icon = link.icon ? ICONS[link.icon] : ArrowUpRight;
const isAccent = i % 5 === 0;
return (
<a
key={link.label}
href={link.href}
className={`group relative ${span} overflow-hidden border-b-2 p-5 transition-colors`}
style={{
borderColor: INK,
borderRightWidth: i % 2 === 0 && span === "col-span-3" ? "2px" : "0",
background: isAccent ? INK : "transparent",
color: isAccent ? PAPER : INK,
}}
>
<span
aria-hidden
className="absolute right-2 top-2 select-none text-[44px] leading-none opacity-15"
style={{
fontFamily: "'Space Grotesk', sans-serif",
fontWeight: 700,
transform: "rotate(-8deg)",
}}
>
{pad(i + 1)}
</span>
<div className="relative z-10 flex items-start gap-3">
<Icon className="mt-0.5 h-4 w-4 shrink-0" strokeWidth={2} />
<div className="min-w-0 flex-1">
<p
className="text-[10px] uppercase tracking-[0.22em] opacity-60"
>
link · {pad(i + 1)}
</p>
<p
className="mt-1.5 truncate text-base"
style={{
fontFamily: "'Space Grotesk', sans-serif",
fontWeight: 600,
}}
>
{link.label}
</p>
{link.badge && (
<span
className="mt-2 inline-block border px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wider"
style={{
borderColor: isAccent ? PAPER : INK,
color: isAccent ? PAPER : INK,
}}
>
{link.badge}
</span>
)}
</div>
</div>
</a>
);
})}
{/* PRODUCT TILES — render any featured-product rich blocks as oversized tiles */}
{products.map((p, idx) => (
<a
key={`product-${idx}`}
href={p.href}
className="group col-span-6 grid grid-cols-[140px_1fr] border-b-2 transition-colors hover:bg-black hover:text-[color:var(--paper)] sm:grid-cols-[180px_1fr]"
style={{ borderColor: INK, ["--paper" as never]: PAPER }}
>
<div className="overflow-hidden border-r-2" style={{ borderColor: INK }}>
<img
src={p.image}
alt={p.title}
width={400}
height={400}
loading="lazy"
className="h-full w-full object-cover transition-transform duration-500 group-hover:scale-[1.04]"
/>
</div>
<div className="flex flex-col justify-between p-5">
<div>
<p className="text-[10px] uppercase tracking-[0.25em] opacity-60">
// featured · drop {pad(idx + 1)}
</p>
<p
className="mt-2 text-base leading-snug"
style={{
fontFamily: "'Space Grotesk', sans-serif",
fontWeight: 700,
}}
>
{p.title}
</p>
</div>
<div className="mt-4 flex items-center justify-between">
<span className="text-lg font-bold">{p.price}</span>
<span className="flex items-center gap-1 text-xs font-medium uppercase tracking-widest">
Buy <ArrowUpRight className="h-3.5 w-3.5" />
</span>
</div>
</div>
</a>
))}
{/* SOCIALS strip */}
{data.socials && data.socials.length > 0 && (
<div
className="col-span-6 flex flex-wrap items-center gap-2 p-4"
style={{ background: INK, color: PAPER }}
>
<span className="mr-2 text-[10px] uppercase tracking-[0.25em] opacity-70">
// socials
</span>
{data.socials.map((s, i) => {
const Icon = ICONS[s.type] ?? Globe;
return (
<a
key={i}
href={s.href}
aria-label={s.type}
className="border p-2 transition-colors hover:bg-[color:var(--paper)] hover:text-[color:var(--ink)]"
style={{
borderColor: PAPER,
["--paper" as never]: PAPER,
["--ink" as never]: INK,
}}
>
<Icon className="h-4 w-4" strokeWidth={2} />
</a>
);
})}
</div>
)}
</div>
<div className="mt-3 flex items-center justify-between text-[10px] uppercase tracking-[0.25em] opacity-70">
<span>{data.links.length + products.length} entries</span>
<span>// end</span>
</div>
</div>
</section>
</>
);
} Claude Code Instructions
CLI Install
npx innovations add brutalist-gridWhere to use it
A brutalist editorial-zine link-in-bio page. Hardcoded paper/ink palette with an orange accent, JetBrains Mono labels and Space Grotesk display.
Pass a typed 'data' prop (LinksInBioData from src/registry/links-in-bio/types.ts) to swap content. With no prop it renders sample data.
Add richBlocks entries with kind 'featured-product' to render oversized product tiles inline with the link grid (great for drops, courses, prints). Each takes image + title + price + href.
In Astro:
import LinksInBioBrutalistGrid from '../components/innovations/links-in-bio/brutalist-grid';
<LinksInBioBrutalistGrid client:load data={myProfile} />
In Next.js:
import LinksInBioBrutalistGrid from '@/components/innovations/links-in-bio/brutalist-grid';
Best for: editorial brands, indie shops, designers, zine-makers — any audience that responds to opinionated, deliberately rough typography.