Bento Grid
zyeon/bento-gridFreeComponent
A responsive tiling layout of mixed-size feature cards, with a pointer-tracked glow and honest click affordances.
Install it
npx shadcn@latest add https://ui.zyeon.ai/r/bento-grid.jsonSource
1"use client"23import * as React from "react"4import { ArrowUpRight } from "lucide-react"5import { cn } from "@/lib/utils"67const REDUCED_MOTION = "(prefers-reduced-motion: reduce)"89function subscribeReducedMotion(callback: () => void) {10 const mq = window.matchMedia(REDUCED_MOTION)11 mq.addEventListener("change", callback)12 return () => mq.removeEventListener("change", callback)13}1415function useReducedMotion() {16 return React.useSyncExternalStore(17 subscribeReducedMotion,18 () => window.matchMedia(REDUCED_MOTION).matches,19 () => false,20 )21}2223type Columns = 2 | 3 | 424type Span = 1 | 2 | 32526// Tailwind only sees class names that exist as literal strings in the source,27// so every column count and span lives in a lookup table — `col-span-${n}`28// would compile away to nothing.29const COLUMNS_CLASS: Record<Columns, string> = {30 2: "grid-cols-1 sm:grid-cols-2",31 3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",32 4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4",33}3435// Spans only kick in once there is more than one column: on phones every card36// is full width anyway, and a span wider than the grid would just be clamped.37const COL_SPAN_CLASS: Record<Span, string> = {38 1: "",39 2: "sm:col-span-2",40 3: "sm:col-span-2 lg:col-span-3",41}4243const ROW_SPAN_CLASS: Record<Span, string> = {44 1: "",45 2: "sm:row-span-2",46 3: "sm:row-span-3",47}4849export interface BentoGridProps extends React.HTMLAttributes<HTMLDivElement> {50 /** Column count from the lg breakpoint up; always 1 on phones and 2 on tablets. */51 columns?: Columns52 /** Gutter in px, applied to both axes. */53 gap?: number54}5556/** The tiling container: a responsive grid with content-sized rows. */57export const BentoGrid = React.forwardRef<HTMLDivElement, BentoGridProps>(58 ({ columns = 3, gap = 16, className, style, children, ...props }, ref) => (59 <div60 className={cn("grid auto-rows-[minmax(8rem,auto)]", COLUMNS_CLASS[columns], className)}61 ref={ref}62 style={{ gap, ...style }}63 {...props}64 >65 {children}66 </div>67 ),68)6970BentoGrid.displayName = "BentoGrid"7172// `title` is widened from the native tooltip attribute to a full ReactNode:73// on a bento tile it is the card's heading, not a hover string.74export interface BentoCardProps extends Omit<React.HTMLAttributes<HTMLElement>, "title"> {75 title: React.ReactNode76 description?: React.ReactNode77 /** Decorative glyph, rendered in a muted chip above the title. */78 icon?: React.ReactNode79 colSpan?: Span80// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from zyeon
All 893 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| A/B Test Resultab-test-result | zyeon | Components | Paid | 2 deps · 2 files | |
| Accordionaccordion | zyeon | Components | Free | 1 dep | |
| Activity Feedactivity-feed | zyeon | Components | Free | 2 deps · 2 files | |
| Activity Heatmapactivity-heatmap | zyeon | Components | Paid | 1 dep · 2 files | |
| Address Formaddress-form | zyeon | Components | Paid | 1 dep | |
| Agent Graphagent-graph | zyeon | Components | Free | 2 deps · 2 files | |
| Agent Handoffagent-handoff | zyeon | Components | Free | 1 dep | |
| Agent Inboxagent-inbox | zyeon | Components | Free | 2 deps · 2 files |
