shadimage
gridcn
exampledata-grid-cell-types-demosource: ok · hit

Data Grid Cell Types Demo

Every built-in cell type in one grid, plus a read-only column, a validate rule, and a custom renderCell override.

npx shadcn add "https://gridcn.vercel.app/r/data-grid-cell-types-demo.json"
free

No selection tags yet — empty means no evidence, not lack of support.

Dependencies

Bundle weight · light

Registry dependencies

DammersCode/gridcn/data-grid

Files2 · source cached 10/14/2026, 8:01:59 AM

registry/default/examples/data-grid-cell-types-demo.tsx
"use client";

import { useMemo, type ReactNode } from "react";
import {
  DataGrid,
  defineColumns,
  type CellRenderProps,
} from "@/registry/default/components/data-grid/data-grid";
import { generateDemoRows, type DemoRow } from "./demo-data";

const columns = defineColumns<DemoRow>()([
  { id: "name", header: "Text", accessorKey: "name", type: "text", width: 55, flex: 1 },
  {
    id: "email",
    header: "Read-only",
    accessorKey: "email",
    type: "text",
    readOnly: true,
    width: 60,
    flex: 1,
  },
  {
    id: "age",
    header: "Validated",
    accessorKey: "age",
    type: "number",
    options: { min: 18, max: 100 },
    validate: (value: unknown) => (typeof value === "number" && value < 18 ? "Must be 18 or older" : null),
    width: 55,
    flex: 1,
  },
  { id: "active", header: "Checkbox", accessorKey: "active", type: "checkbox", width: 50, flex: 1 },
  {
    id: "role",
    header: "Select",
    accessorKey: "role",
    type: "select",
    options: {
      choices: [
        { value: "Admin", label: "Admin" },
        { value: "User", label: "User" },
        { value: "Editor", label: "Editor" },
        { value: "Viewer", label: "Viewer" },
        { value: "Manager", label: "Manager" },
      ],
    },
    width: 55,
    flex: 1,
  },
  {
    id: "joined",
    header: "Date",
    accessorKey: "joined",
    type: "date",
    options: { displayFormat: { year: "numeric", month: "short", day: "numeric" } },
    width: 55,
    flex: 1,
  },
  {
    id: "score",
    header: "renderCell",
    accessorKey: "score",
    type: "number",
    options: { min: 0, max: 100 },
    // Display override: same number type/pipeline (edit/paste/sort unchanged), custom rendering only.
    renderCell: ({ value }: CellRenderProps<DemoRow, number | null>) => (
      <div className="flex h-full items-center gap-2 px-2 tabular-nums">
        <div className="h-1.5 flex-1 overflow-hidden bg-muted">
          <div className="h-full bg-primary" style={{ width: `${value ?? 0}%` }} />
        </div>
        <span className="text-xs text-muted-foreground">{value}</span>
      </div>
    ),
    width: 60,
    flex: 1,
  },
] as const);

/**
 * Every built-in cell type in one grid, plus a read-only column, a `validate` rule (Age rejects
 * under-18 edits), and a `renderCell` override on Score that keeps the number type's edit/sort/
 * clipboard pipeline but renders a progress bar instead of plain text.
 */
export default function DataGridCellTypesDemo(): ReactNode {
  const rows = useMemo(() => generateDemoRows(8), []);

  return (
    <div className="w-full flex flex-col gap-3">
      <p className="text-sm text-muted-foreground">
        Try each column's editor: Text is plain, Read-only refuses edits, Validated rejects an age
        under 18 and keeps the editor open with a message under the cell, and renderCell shows a
        progress bar over the same number type.
      </p>
      <div className="h-[360px] overflow-hidden rounded-md border border-border">
        <DataGrid
          defaultData={rows}
          columns={columns}
          getRowId={(row) => row.id}
          className="h-full rounded-none border-none"
        />
      </div>
    </div>
  );
}
registry/default/examples/demo-data.ts
/** Deterministic LCG so SSR/CSR markup match without Math.random(); shared across example rows. */
function createSeededLcg(seed: number) {
  let state = seed;
  return () => {
    state = (state * 1103515245 + 12345) & 0x7fffffff;
    return state / 0x7fffffff;
  };
}

export type DemoRow = {
  id: string;
  name: string;
  email: string;
  age: number;
  active: boolean;
  role: string;
  joined: string;
  score: number;
};

const ROLES = ["Admin", "User", "Editor", "Viewer", "Manager"] as const;
const ADJECTIVES = ["Eager", "Quick", "Silent", "Bold", "Swift"] as const;
const NOUNS = ["Eagle", "Lion", "Tiger", "Bear", "Wolf"] as const;

/** Generates `count` deterministic demo rows for example previews (seed 42, stable across renders). */
export function generateDemoRows(count: number, seed = 42): DemoRow[] {
  const next = createSeededLcg(seed);
  const rows: DemoRow[] = [];
  for (let i = 0; i < count; i++) {
    rows.push({
      id: `row-${i}`,
      name: `${ADJECTIVES[Math.floor(next() * ADJECTIVES.length)]} ${NOUNS[Math.floor(next() * NOUNS.length)]}`,
      email: `user${i}@example.com`,
      age: Math.floor(next() * 50) + 18,
      active: next() > 0.5,
      role: ROLES[Math.floor(next() * ROLES.length)]!, // ROLES is a fixed non-empty literal array
      joined: `${2020 + Math.floor(next() * 5)}-${String(Math.floor(next() * 12) + 1).padStart(2, "0")}-${String(Math.floor(next() * 28) + 1).padStart(2, "0")}`,
      score: Math.floor(next() * 100),
    });
  }
  return rows;
}

More from gridcn

Browse all components in this library →