Pattern gallery

Attribute / spec key-value grid

A record's fields as one label/value grid, sectioned and reused wherever the record surfaces.

What this solves

Information hierarchy and reuse discipline: a record's fields need one predictable label/value shape everywhere they surface, so a reader doesn't relearn the layout moving between the peek panel, the modal, and the full tab. Speedway holds this in one real component; walmart's version has drifted into two identical copies, which is exactly the risk a shared grid closes.
Use it when
  • A generated field's value needs the same shape on the peek panel, the modal, and the full tabspeedway ContentFieldsTable: one Table-backed component, three call sites across ProductItem.tsx and part-detail-tabs.tsx
  • A record's identity and taxonomy fields need a compact label/value summary, not a tablewalmart-mvp DetailBlock/DetailRow: a dl grid with a mono flag and an italic n/a fallback, defined separately in ItemDetailPanel.tsx and TaxonomyTab.tsx

Rendered

Fixture data; check both themes.

Brake pad, front axle

Generated 2 minutes ago
Identity
SKUsku
BRK-Q3-40821
UPCupc
038932107744
Brand
Raybestos
Specifications
Material
Semi-metallic composite with a ceramic-blended friction layer for quieter stops
Rotor diameter
11.65 in
Bolt pattern
Required field missing
Marketing content
Description
Engineered for daily-driver stopping power without the squeal.Generated by gemini-3.5-pro, run #4821
Fitment notes
n/a
patterns/attribute-spec-grid/example.tsxCopy this into a fresh route and it renders as above.
"use client";
import { Card, FieldChip, Tooltip } from "@versable-git/ui";
// The row vocabulary a record's fields actually need, gathered into one
// fixture record. mono + n/a fallback come from walmart-mvp's DetailRow
// (ItemDetailPanel.tsx:411-430); the raw field key beside a label is
// FieldChip's own documented job (a data field's name, wherever one is
// shown); the required-but-missing warning treatment comes from walmart-mvp's
// separate AttributesList (asterisk-prefixed keys in warning tone,
// ItemDetailPanel.tsx:430-453); "Generated by" echoes speedway's
// ContentFieldsTable "By" column, which real usage gates to staff.
type AttributeRow = {
label: string;
fieldKey?: string;
value?: string | null;
mono?: boolean;
tooltip?: string;
generatedBy?: string;
critical?: boolean;
};
type AttributeSection = {
label: string;
rows: AttributeRow[];
};
const SECTIONS: AttributeSection[] = [
{
label: "Identity",
rows: [
{ label: "SKU", fieldKey: "sku", value: "BRK-Q3-40821", mono: true },
{ label: "UPC", fieldKey: "upc", value: "038932107744", mono: true },
{ label: "Brand", value: "Raybestos" },
],
},
{
label: "Specifications",
rows: [
{
label: "Material",
value: "Semi-metallic composite with a ceramic-blended friction layer for quieter stops",
tooltip: "Semi-metallic composite with a ceramic-blended friction layer for quieter stops",
},
{ label: "Rotor diameter", value: "11.65 in" },
{ label: "Bolt pattern", value: null, critical: true },
],
},
{
label: "Marketing content",
rows: [
{
label: "Description",
value: "Engineered for daily-driver stopping power without the squeal.",
generatedBy: "gemini-3.5-pro, run #4821",
},
{ label: "Fitment notes", value: null },
],
},
];
function Row({ row }: { row: AttributeRow }) {
const valueClass = ["m-0 text-sm", row.mono && "text-base-content/70 font-mono text-xs"]
.filter(Boolean)
.join(" ");
return (
<>
<dt className="text-base-content/65 flex items-center gap-1.5 text-sm">
{row.label}
{row.fieldKey && <FieldChip>{row.fieldKey}</FieldChip>}
</dt>
<dd className={valueClass}>
{row.value ? (
row.tooltip ? (
<Tooltip content={row.tooltip} placement="top-start">
<span className="block max-w-[280px] truncate">{row.value}</span>
</Tooltip>
) : (
row.value
)
) : (
<span className={row.critical ? "text-warning italic" : "text-base-content/65 italic"}>
{row.critical ? "Required field missing" : "n/a"}
</span>
)}
{row.generatedBy && (
<span className="text-base-content/45 mt-0.5 block text-xs">Generated by {row.generatedBy}</span>
)}
</dd>
</>
);
}
function AttributeGrid({ sections }: { sections: AttributeSection[] }) {
return (
<div className="flex flex-col gap-4">
{sections.map((section) => (
<div key={section.label} className="flex flex-col gap-1.5">
<span className="text-base-content/65 text-xs font-semibold tracking-wide uppercase">
{section.label}
</span>
<dl className="m-0 grid grid-cols-[max-content_1fr] gap-x-4 gap-y-2">
{section.rows.map((row) => (
<Row key={row.label} row={row} />
))}
</dl>
</div>
))}
</div>
);
}
export function AttributeSpecGrid() {
return (
<Card title="Brake pad, front axle" subtitle="Generated 2 minutes ago" noAnimate>
<AttributeGrid sections={SECTIONS} />
</Card>
);
}

Where it ships

  • speedway/app/components/content-fields.tsx:172-179ContentFieldsTable, its own docstring: shared by the part page, the peek panel, and the preview modal, so a generated field looks the same wherever someone finds it (called from ProductItem.tsx:458,531 and part-detail-tabs.tsx:233)
  • walmart-mvp/frontend/src/features/catalog/ItemDetailPanel.tsx:400-430DetailBlock/DetailRow, a dl grid with a mono flag; the identical shape is redefined, not imported, at TaxonomyTab.tsx:475-483

App-specific: Speedway's version rides inside a Table (Field, Content, and a staff-gated By/provenance column); walmart's is a plain semantic dl, and its required-attribute warning treatment comes from a separate AttributesList component (asterisk-prefixed keys in warning tone, ItemDetailPanel.tsx:430-453). Neither canon doc names this composite outright; the closest is doc 5 §A8's dl-as-stat-list bullet ('a two-column dl grid for label/value summaries inside a card when a table is too heavy, admin team usage'), which this recipe follows. Real usage also needs the staff gate speedway applies to provenance, and an empty-vs-critical distinction driven by the record's own required-field list, both left out of the fixture.

@versable-git/ui · composites proven in the apps