Componentmedia0.7 KB gzipZero dependencies
Inventory Grid
Tappable slot matrix with fill states.
Preview
Live Preview
Installation
Tokens guide →Add to your project via CLI (zero dependencies, code you own):
npx bigbullui add inventory-gridOr install the full npm package:
npm install bigbulluiUsage
Open in StackBlitzimport { InventoryGrid } from "@/components/ui/inventory-grid";
<InventoryGrid />Usage guidance
Use Inventory Grid when a ticket stub surface needs Tappable slot matrix with fill states. Keep props minimal and prefer composition with sibling stubs.
Avoid Inventory Grid for long form flows or dense data grids where a dedicated layout block fits better.
Source code
inventory-grid.tsxZero dependencies (only React + utils). Copy and paste directly into your project:
"use client";
import * as React from "react";
import { cn } from "./lib/utils";
export interface InventoryGridProps extends React.HTMLAttributes<HTMLDivElement> {
slots?: number;
filled?: number;
onPick?: (index: number) => void;
}
/** Inventory grid: tappable slot matrix with fill states. */
export function InventoryGrid({ slots = 12, filled = 7, onPick, className, ...props }: InventoryGridProps) {
return (
<div role="grid" aria-label={`Inventory ${filled} of ${slots} filled`} className={cn("grid touch-none grid-cols-4 gap-1.5 select-none", className)} style={{ touchAction: "none" }} {...props}>
{Array.from({ length: slots }).map((_, i) => (
<button
key={i}
type="button"
role="gridcell"
aria-label={i < filled ? `Slot ${i + 1} occupied` : `Slot ${i + 1} empty`}
onClick={() => onPick?.(i)}
className={cn(
"flex min-h-11 min-w-11 touch-none items-center justify-center rounded-md border-2 border-dashed font-mono text-[10px] font-bold focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
i < filled ? "border-foreground bg-secondary text-foreground" : "border-border bg-card text-muted-foreground"
)}
style={{ touchAction: "none" }}
>
{i < filled ? `×${(i % 9) + 1}` : "—"}
</button>
))}
</div>
);
}