Kosmesis
Components

Bento Grid

A card-styled grid for irregularly-sized tiles. Purely presentational — no Morphos equivalent.

Installation

npx kosmesis add bento-grid
pnpm dlx kosmesis add bento-grid
yarn dlx kosmesis add bento-grid
bunx kosmesis add bento-grid

Copy and paste the following code into your project.

bento-grid.tsx
import { StatelessComponent } from "@praxisjs/core";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import { cn } from "@/lib/utils";export interface BentoGridProps {  cols?: number;  class?: string;  id?: string;  children?: Children;}@Component()export class BentoGrid extends StatelessComponent<BentoGridProps> {  render() {    const { cols = 3, class: cls, id, children } = this.props;    return (      <div        id={id}        data-slot="bento-grid"        class={cn("grid w-full auto-rows-[12rem] gap-4", cls)}        style={{ gridTemplateColumns: `repeat(${String(cols)}, minmax(0, 1fr))` }}      >        {children}      </div>    );  }}export interface BentoGridItemProps {  colSpan?: number;  rowSpan?: number;  class?: string;  id?: string;  children?: Children;}@Component()export class BentoGridItem extends StatelessComponent<BentoGridItemProps> {  render() {    const { colSpan, rowSpan, class: cls, id, children } = this.props;    return (      <div        id={id}        data-slot="bento-grid-item"        class={cn(          "group relative flex flex-col justify-between overflow-hidden rounded-xl border bg-card p-5 text-card-foreground shadow-sm transition-shadow hover:shadow-md",          cls,        )}        // "auto" not `undefined` — an undefined gridColumn/gridRow serializes to the literal        // string "undefined", corrupting grid placement.        style={{          gridColumn: colSpan !== undefined ? `span ${String(colSpan)} / span ${String(colSpan)}` : "auto",          gridRow: rowSpan !== undefined ? `span ${String(rowSpan)} / span ${String(rowSpan)}` : "auto",        }}      >        {children}      </div>    );  }}

Install the following dependencies:

npm install @praxisjs/css
pnpm add @praxisjs/css
yarn add @praxisjs/css
bun add @praxisjs/css

Copy and paste the following code into your project.

bento-grid.tsx
import { StatelessComponent } from "@praxisjs/core";import { cx, Stylesheet, Styled, tokenVars } from "@praxisjs/css";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import { KosmesisTokens } from "@/lib/kosmesis-theme";const t = tokenVars(KosmesisTokens);class BentoGridStyles extends Stylesheet {  $root = this.css({ display: "grid", width: "100%", gridAutoRows: "12rem", gap: "1rem" });  $item = this.css({    position: "relative",    display: "flex",    flexDirection: "column",    justifyContent: "space-between",    overflow: "hidden",    borderRadius: "0.75rem",    border: `1px solid ${t.border}`,    backgroundColor: t.card,    color: t.cardForeground,    padding: "1.25rem",    boxShadow: "0 1px 2px 0 rgb(0 0 0 / 0.05)",    transition: "box-shadow 150ms ease",  }).on("&:hover", { boxShadow: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)" });}export interface BentoGridProps {  cols?: number;  class?: string;  id?: string;  children?: Children;}@Component()export class BentoGrid extends StatelessComponent<BentoGridProps> {  @Styled(BentoGridStyles) $s!: BentoGridStyles;  render() {    const { cols = 3, class: cls, id, children } = this.props;    return (      <div        id={id}        data-slot="bento-grid"        class={cx(this.$s.$root, cls)}        style={{ gridTemplateColumns: `repeat(${String(cols)}, minmax(0, 1fr))` }}      >        {children}      </div>    );  }}export interface BentoGridItemProps {  colSpan?: number;  rowSpan?: number;  class?: string;  id?: string;  children?: Children;}@Component()export class BentoGridItem extends StatelessComponent<BentoGridItemProps> {  @Styled(BentoGridStyles) $s!: BentoGridStyles;  render() {    const { colSpan, rowSpan, class: cls, id, children } = this.props;    return (      <div        id={id}        data-slot="bento-grid-item"        class={cx(this.$s.$item, cls)}        // "auto" not `undefined` — an undefined gridColumn/gridRow serializes to the literal        // string "undefined", corrupting grid placement.        style={{          gridColumn: colSpan !== undefined ? `span ${String(colSpan)} / span ${String(colSpan)}` : "auto",          gridRow: rowSpan !== undefined ? `span ${String(rowSpan)} / span ${String(rowSpan)}` : "auto",        }}      >        {children}      </div>    );  }}

Examples

About

Purely presentational — no Morphos equivalent. Same runtime cols/colSpan/rowSpan-via-inline-style approach as Grid, styled as bordered cards (bg-card) instead of bare tracks.

Usage

import { BentoGrid, BentoGridItem } from "@/components/ui/bento-grid";

<BentoGrid cols={3}>
  <BentoGridItem colSpan={2}>
    <h3>Analytics</h3>
    <p>Track everything in one place.</p>
  </BentoGridItem>
  <BentoGridItem>
    <h3>Team</h3>
  </BentoGridItem>
</BentoGrid>

Props

BentoGrid

PropTypeDefault
colsnumber3
classstring

BentoGridItem

PropTypeDefault
colSpannumber
rowSpannumber
classstring

On this page