Bento Grid
loomui/bento-gridFreeComponent
A grid of tiles of different sizes that arrive one after another when the grid is reached.
Live preview
live · rendered by the registry
Rendered by loomui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://loomui.design/r/bento-grid.jsonSource
1"use client"23import * as React from "react"45import { cn } from "@/lib/utils"67export interface BentoGridProps extends React.ComponentProps<"div"> {8 /** Milliseconds between one tile arriving and the next. */9 stagger?: number10 /** Run on mount instead of holding until the grid scrolls into view. */11 startOnView?: boolean12 /** Render the finished layout with no arrival. */13 disabled?: boolean14}1516/**17 * The grid owns the arrival, not the tiles: it hands each tile its place in the18 * order, so tiles stay plain markup and can be composed, wrapped or reordered19 * without carrying an index around.20 */21export function BentoGrid({22 children,23 className,24 stagger = 70,25 startOnView = true,26 disabled = false,27 style,28 ...props29}: BentoGridProps) {30 const ref = React.useRef<HTMLDivElement>(null)31 const [active, setActive] = React.useState(!startOnView)3233 React.useEffect(() => {34 const root = ref.current35 if (!root) {36 return37 }3839 for (const [index, tile] of Array.from(40 root.querySelectorAll<HTMLElement>("[data-slot='bento-card']")41 ).entries()) {42 tile.style.setProperty("--bento-delay", `${index * stagger}ms`)43 }44 }, [stagger, children])4546 React.useEffect(() => {47 if (!startOnView || disabled) {48 return49 }5051 const root = ref.current52 if (!root || typeof IntersectionObserver === "undefined") {53 setActive(true)54 return55 }5657 const observer = new IntersectionObserver(58 ([entry]) => {59 if (entry.isIntersecting) {60 setActive(true)61 observer.disconnect()62 }63 },64 { threshold: 0.15 }65 )6667 observer.observe(root)68 return () => observer.disconnect()69 }, [startOnView, disabled])7071 return (72 <div73 ref={ref}74 data-slot="bento-grid"75 data-active={disabled || active ? "" : undefined}76 className={cn(77 "group grid auto-rows-[minmax(9rem,auto)] grid-cols-1 gap-4 sm:grid-cols-3",78 className79 )}80 style={style}81 {...props}82 >83 {children}84 </div>85 )86}8788export interface BentoCardProps extends Omit<89 React.ComponentProps<"div">,90 "title"91> {92 /** Heading for the tile. */93 title?: React.ReactNode94 /** Supporting line under the title. */95 description?: React.ReactNode96 /** Mark shown above the title. A glyph or a small icon. */97 icon?: React.ReactNode98 /** Anything pinned to the bottom of the tile. A link, usually. */99 footer?: React.ReactNode100}101102export function BentoCard({103// … truncated
What it pulls in
Other registry items
Files it writes
More from loomui
All 91 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Aurora Backdropaurora-backdrop | loomui | Components | Free | no deps | |
| Card Stackcard-stack | loomui | Components | Free | no deps | |
| Compare Slidercompare-slider | loomui | Components | Free | no deps | |
| Confetti Buttonconfetti-button | loomui | Components | Free | no deps | |
| Count Upcount-up | loomui | Components | Free | no deps | |
| Credit Cardcredit-card | loomui | Components | Free | no deps | |
| Drawerdrawer | loomui | Components | Free | 1 dep | |
| Elastic Tabselastic-tabs | loomui | Components | Free | no deps |
