Control how cells display content by setting the cellRenderer
property on a column. This is the
main way to customize cell appearance in LyteNyte Grid.
The cellRenderer
property accepts either:
Pass a React function component directly to cellRenderer
to define how each cell in that column is
rendered.
"use client";
import { Grid, useClientRowDataSource } from "@1771technologies/lytenyte-pro";
import "@1771technologies/lytenyte-pro/grid.css";
import type { Column } from "@1771technologies/lytenyte-pro/types";
import { companiesWithPricePerf } from "@1771technologies/sample-data/companies-with-price-performance";
import { useId } from "react";
import { Sparklines, SparklinesLine } from "react-sparklines";
type PerformanceData = (typeof companiesWithPricePerf)[number];
const columns: Column<PerformanceData>[] = [
{ id: "Company" },
{ id: "Founded" },
{ id: "Employee Cnt" },
{
id: "1 Year Perf",
cellRenderer: (p) => {
const field = p.grid.api.columnField(p.column, p.row) as number[];
return (
<div
style={{
width: "100%",
height: "100%",
boxSizing: "border-box",
padding: 4,
}}
>
<Sparklines data={field}>
<SparklinesLine color="blue" />
</Sparklines>
</div>
);
},
},
{
id: "Price",
cellRenderer: (p) => {
const field = p.grid.api.columnField(p.column, p.row) as string;
return (
<div
style={{
width: "100%",
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "end",
paddingInline: 8,
boxSizing: "border-box",
fontFamily: "monospace",
}}
>
${field}
</div>
);
},
},
];
export default function CellRenderers() {
const ds = useClientRowDataSource({
data: companiesWithPricePerf,
});
const grid = Grid.useLyteNyte({
gridId: useId(),
rowDataSource: ds,
columns,
});
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.HeaderCell
key={c.id}
cell={c}
className="flex w-full h-full capitalize px-2 items-center"
/>
);
})}
</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.Cell
key={c.id}
cell={c}
className="text-sm flex items-center px-2 h-full w-full"
/>
);
})}
</Grid.Row>
);
})}
</Grid.RowsCenter>
</Grid.RowsContainer>
</Grid.Viewport>
</Grid.Root>
</div>
);
}
For reusability and cleaner column definitions, register cell renderers and reference them by key.
Pass a string to cellRenderer
that matches a key in your registered renderers. Register renderers
through the cellRenderers
property in grid state.
"use client";
import { Grid, useClientRowDataSource } from "@1771technologies/lytenyte-pro";
import "@1771technologies/lytenyte-pro/grid.css";
import type {
CellRendererParams,
Column,
} from "@1771technologies/lytenyte-pro/types";
import { companiesWithPricePerf } from "@1771technologies/sample-data/companies-with-price-performance";
import { useId } from "react";
import { Sparklines, SparklinesLine } from "react-sparklines";
type PerformanceData = (typeof companiesWithPricePerf)[number];
const columns: Column<PerformanceData>[] = [
{ id: "Company" },
{ id: "Founded" },
{ id: "Employee Cnt" },
{
id: "1 Year Perf",
cellRenderer: "line-renderer",
},
{
id: "Price",
cellRenderer: "dollar-renderer",
},
];
export default function CellRenderersRegistered() {
const ds = useClientRowDataSource({
data: companiesWithPricePerf,
});
const grid = Grid.useLyteNyte({
gridId: useId(),
rowDataSource: ds,
columns,
cellRenderers: {
"line-renderer": SparklineRenderer,
"dollar-renderer": DollarRenderer,
},
});
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.HeaderCell
key={c.id}
cell={c}
className="flex w-full h-full capitalize px-2 items-center"
/>
);
})}
</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.Cell
key={c.id}
cell={c}
className="text-sm flex items-center px-2 h-full w-full"
/>
);
})}
</Grid.Row>
);
})}
</Grid.RowsCenter>
</Grid.RowsContainer>
</Grid.Viewport>
</Grid.Root>
</div>
);
}
function DollarRenderer(p: CellRendererParams<PerformanceData>) {
const field = p.grid.api.columnField(p.column, p.row) as string;
return (
<div
style={{
width: "100%",
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "end",
paddingInline: 8,
boxSizing: "border-box",
fontFamily: "monospace",
}}
>
${field}
</div>
);
}
function SparklineRenderer(p: CellRendererParams<PerformanceData>) {
const field = p.grid.api.columnField(p.column, p.row) as number[];
return (
<div
style={{
width: "100%",
height: "100%",
boxSizing: "border-box",
padding: 4,
}}
>
<Sparklines data={field}>
<SparklinesLine color="blue" />
</Sparklines>
</div>
);
}
This pattern keeps column definitions serializable and makes renderers easier to reuse.
All rendered cells in LyteNyte Grid are React components and can use any React hook. However, cells mount and unmount frequently as users scroll. Local component state will not persist between mounts.
To maintain persistent cell state across scrolling, manage the state at the grid level and pass it down to individual cells.