Row Detail
Create expandable detail sections beneath rows in LyteNyte Grid with customizable React components, expansion controls, and programmatic API methods.
LyteNyte Grid lets you add expandable detail sections beneath individual rows. This feature, called Row Detail (also known as Master Detail), lets you render any React component in the expanded area.
Enable Row Detail
Expand a row's detail area by adding its id to the rowDetailExpansions
state in LyteNyte Grid. This enables expansion for specific rows.
Provide a React component through the rowDetailRenderer property
to define the content in each row's detail section.
Row Detail
"use client";import { Grid, useClientRowDataSource } from "@1771technologies/lytenyte-pro";import "@1771technologies/lytenyte-pro/grid.css";import type { Column, RowLeaf } from "@1771technologies/lytenyte-pro/types";import { companiesWithPricePerf } from "@1771technologies/sample-data/companies-with-price-performance";import { useId, useMemo } from "react";import { Area, AreaChart, CartesianGrid, ResponsiveContainer, XAxis, YAxis } from "recharts";type PerformanceData = (typeof companiesWithPricePerf)[number];const columns: Column<PerformanceData>[] = [{ id: "Company" },{ id: "Founded" },{ id: "Employee Cnt" },{ id: "Country" },{ id: "Price" },];export default function RowDetail() {const ds = useClientRowDataSource({data: companiesWithPricePerf,});const grid = Grid.useLyteNyte({gridId: useId(),rowDataSource: ds,columns,rowDetailExpansions: new Set(["0"]),rowDetailRenderer: (p) => {if (!grid.api.rowIsLeaf(p.row)) return;return (<divstyle={{width: "100%",height: "100%",boxSizing: "border-box",padding: "20px 20px 20px 0px",}}><PriceChart row={p.row} /></div>);},});const view = grid.view.useValue();return (<div className="lng-grid" style={{ height: 500 }}><Grid.Root grid={grid}><Grid.Viewport><Grid.Header>{view.header.layout.map((row, i) => {return (<Grid.HeaderRow key={i} headerRowIndex={i}>{row.map((c) => {if (c.kind === "group") return null;return (<Grid.HeaderCellkey={c.id}cell={c}className="flex h-full w-full items-center px-2 capitalize"/>);})}</Grid.HeaderRow>);})}</Grid.Header><Grid.RowsContainer><Grid.RowsCenter>{view.rows.center.map((row) => {if (row.kind === "full-width") return null;return (<Grid.Row row={row} key={row.id}>{row.cells.map((c) => {return (<Grid.Cellkey={c.id}cell={c}className="flex h-full w-full items-center px-2 text-sm"/>);})}</Grid.Row>);})}</Grid.RowsCenter></Grid.RowsContainer></Grid.Viewport></Grid.Root></div>);}function PriceChart({ row }: { row: RowLeaf<PerformanceData> }) {const data = useMemo(() => {if (!row.data) return [];const weeks: Record<string, { week: number; [key: string]: number }> = Object.fromEntries(Array.from({ length: 52 }, (_, i) => [i + 1, { week: i + 1 }]),);const data = row.data["1 Year Perf"];data.forEach((dp, i) => {weeks[i + 1][row.id] = dp;});return Object.values(weeks).sort((l, r) => l.week - r.week);}, [row.data, row.id]);return (<ResponsiveContainer height="100%" width="100%"><AreaChart data={data}><defs><linearGradient key={row.id} id={row.id} x1="0" y1="0" x2="0" y2="1"><stop offset="5%" stopColor={color.stop5} stopOpacity={0.8} /><stop offset="95%" stopColor={color.stop95} stopOpacity={0} /></linearGradient></defs><XAxis dataKey="week" /><YAxis /><CartesianGrid strokeDasharray="3 3" /><Areakey={row.id}type="monotone"dataKey={row.id}stroke={color.solid}fillOpacity={1}fill={`url(#${row.id})`}/></AreaChart></ResponsiveContainer>);}const color = {name: "Ruby Red",solid: "#2de045",stop5: "#e6fbe6",stop95: "#3ee362",};
Set Row Detail Height
Control the detail area's height with the rowDetailHeight
property. Specify a fixed pixel value or use the
string "auto" to return a calculated pixel height.
Row Detail Height
"use client";import { Grid, useClientRowDataSource } from "@1771technologies/lytenyte-pro";import "@1771technologies/lytenyte-pro/grid.css";import type { Column, RowLeaf } from "@1771technologies/lytenyte-pro/types";import { companiesWithPricePerf } from "@1771technologies/sample-data/companies-with-price-performance";import { useId, useMemo } from "react";import { Area, AreaChart, CartesianGrid, ResponsiveContainer, XAxis, YAxis } from "recharts";type PerformanceData = (typeof companiesWithPricePerf)[number];const columns: Column<PerformanceData>[] = [{ id: "Company" },{ id: "Founded" },{ id: "Employee Cnt" },{ id: "Country" },{ id: "Price" },];export default function RowDetailHeight() {const ds = useClientRowDataSource({data: companiesWithPricePerf,});const grid = Grid.useLyteNyte({gridId: useId(),rowDataSource: ds,columns,rowDetailHeight: 200,rowDetailExpansions: new Set(["0"]),rowDetailRenderer: (p) => {if (!grid.api.rowIsLeaf(p.row)) return;return (<divstyle={{width: "100%",height: "100%",boxSizing: "border-box",padding: "20px 20px 20px 0px",}}><PriceChart row={p.row} /></div>);},});const view = grid.view.useValue();return (<div className="lng-grid" style={{ height: 500 }}><Grid.Root grid={grid}><Grid.Viewport><Grid.Header>{view.header.layout.map((row, i) => {return (<Grid.HeaderRow key={i} headerRowIndex={i}>{row.map((c) => {if (c.kind === "group") return null;return (<Grid.HeaderCellkey={c.id}cell={c}className="flex h-full w-full items-center px-2 capitalize"/>);})}</Grid.HeaderRow>);})}</Grid.Header><Grid.RowsContainer><Grid.RowsCenter>{view.rows.center.map((row) => {if (row.kind === "full-width") return null;return (<Grid.Row row={row} key={row.id}>{row.cells.map((c) => {return (<Grid.Cellkey={c.id}cell={c}className="flex h-full w-full items-center px-2 text-sm"/>);})}</Grid.Row>);})}</Grid.RowsCenter></Grid.RowsContainer></Grid.Viewport></Grid.Root></div>);}function PriceChart({ row }: { row: RowLeaf<PerformanceData> }) {const data = useMemo(() => {if (!row.data) return [];const weeks: Record<string, { week: number; [key: string]: number }> = Object.fromEntries(Array.from({ length: 52 }, (_, i) => [i + 1, { week: i + 1 }]),);const data = row.data["1 Year Perf"];data.forEach((dp, i) => {weeks[i + 1][row.id] = dp;});return Object.values(weeks).sort((l, r) => l.week - r.week);}, [row.data, row.id]);return (<ResponsiveContainer height="100%" width="100%"><AreaChart data={data}><defs><linearGradient key={row.id} id={row.id} x1="0" y1="0" x2="0" y2="1"><stop offset="5%" stopColor={color.stop5} stopOpacity={0.8} /><stop offset="95%" stopColor={color.stop95} stopOpacity={0} /></linearGradient></defs><XAxis dataKey="week" /><YAxis /><CartesianGrid strokeDasharray="3 3" /><Areakey={row.id}type="monotone"dataKey={row.id}stroke={color.solid}fillOpacity={1}fill={`url(#${row.id})`}/></AreaChart></ResponsiveContainer>);}const color = {name: "Ruby Red",solid: "#2de045",stop5: "#e6fbe6",stop95: "#3ee362",};
Add a Row Detail Marker
By default, LyteNyte Grid does not include a built-in component
for expanding or collapsing a row's detail area. Use the
api.rowDetailToggle method to toggle or set a row's expansion state.
A common approach is to use LyteNyte Grid's marker column as the toggle control.
Example:
Row Detail Marker
"use client";import { Grid, useClientRowDataSource } from "@1771technologies/lytenyte-pro";import "@1771technologies/lytenyte-pro/grid.css";import { ChevronDownIcon, ChevronRightIcon } from "@1771technologies/lytenyte-pro/icons";import type { Column, RowLeaf } from "@1771technologies/lytenyte-pro/types";import { companiesWithPricePerf } from "@1771technologies/sample-data/companies-with-price-performance";import { useId, useMemo } from "react";import { Area, AreaChart, CartesianGrid, ResponsiveContainer, XAxis, YAxis } from "recharts";type PerformanceData = (typeof companiesWithPricePerf)[number];const columns: Column<PerformanceData>[] = [{ id: "Company" },{ id: "Founded" },{ id: "Employee Cnt" },{ id: "Country" },{ id: "Price" },];export default function RowDetailMarker() {const ds = useClientRowDataSource({data: companiesWithPricePerf,});const grid = Grid.useLyteNyte({gridId: useId(),rowDataSource: ds,columns,columnMarkerEnabled: true,columnMarker: {cellRenderer: ({ grid, row }) => {const isExpanded = grid.api.rowDetailIsExpanded(row);return (<buttononClick={() => grid.api.rowDetailToggle(row)}className="flex h-full w-full min-w-full items-center justify-center">{isExpanded ? <ChevronDownIcon /> : <ChevronRightIcon />}</button>);},},rowDetailExpansions: new Set(["0"]),rowDetailRenderer: (p) => {if (!grid.api.rowIsLeaf(p.row)) return;return (<divstyle={{width: "100%",height: "100%",boxSizing: "border-box",padding: "20px 20px 20px 0px",}}><PriceChart row={p.row} /></div>);},});const view = grid.view.useValue();return (<div className="lng-grid" style={{ height: 500 }}><Grid.Root grid={grid}><Grid.Viewport><Grid.Header>{view.header.layout.map((row, i) => {return (<Grid.HeaderRow key={i} headerRowIndex={i}>{row.map((c) => {if (c.kind === "group") return null;return (<Grid.HeaderCellkey={c.id}cell={c}className="flex h-full w-full items-center px-2 capitalize"/>);})}</Grid.HeaderRow>);})}</Grid.Header><Grid.RowsContainer><Grid.RowsCenter>{view.rows.center.map((row) => {if (row.kind === "full-width") return null;return (<Grid.Row row={row} key={row.id}>{row.cells.map((c) => {return (<Grid.Cellkey={c.id}cell={c}className="flex h-full w-full items-center px-2 text-sm"/>);})}</Grid.Row>);})}</Grid.RowsCenter></Grid.RowsContainer></Grid.Viewport></Grid.Root></div>);}function PriceChart({ row }: { row: RowLeaf<PerformanceData> }) {const data = useMemo(() => {if (!row.data) return [];const weeks: Record<string, { week: number; [key: string]: number }> = Object.fromEntries(Array.from({ length: 52 }, (_, i) => [i + 1, { week: i + 1 }]),);const data = row.data["1 Year Perf"];data.forEach((dp, i) => {weeks[i + 1][row.id] = dp;});return Object.values(weeks).sort((l, r) => l.week - r.week);}, [row.data, row.id]);return (<ResponsiveContainer height="100%" width="100%"><AreaChart data={data}><defs><linearGradient key={row.id} id={row.id} x1="0" y1="0" x2="0" y2="1"><stop offset="5%" stopColor={color.stop5} stopOpacity={0.8} /><stop offset="95%" stopColor={color.stop95} stopOpacity={0} /></linearGradient></defs><XAxis dataKey="week" /><YAxis /><CartesianGrid strokeDasharray="3 3" /><Areakey={row.id}type="monotone"dataKey={row.id}stroke={color.solid}fillOpacity={1}fill={`url(#${row.id})`}/></AreaChart></ResponsiveContainer>);}const color = {name: "Ruby Red",solid: "#2de045",stop5: "#e6fbe6",stop95: "#3ee362",};
Manage Row Detail Expansions
The rowDetailExpansions property in grid state stores
the ids of expanded rows. Update this value programmatically
to change which rows show their detail sections.
Use these LyteNyte Grid API methods to control row detail programmatically:
rowDetailIsExpanded- Returnstrueif a row is expanded.rowDetailToggle- Switches a row's expansion state.rowDetailRenderedHeight- Returns the current visible height (in pixels) of a row's detail section.
See the API Reference for complete details.
Row Sorting
Configure and control row sorting in LyteNyte Grid using sort models, column configurations, and programmatic API methods.
Row Pagination
Implement and configure row pagination in LyteNyte Grid to divide large datasets into manageable pages with customizable page sizes and navigation controls.