LyteNyte Grid's floating row is a specialized header row that appears below the main column headers. It lets you render custom components for each column. While often used for filtering interfaces, you can use it for any component type.
Enable the floating header row by setting floatingRowEnabled
to true
in the grid configuration. Once enabled, a row appears below the column
headers with cells for each column. Each floating cell's content comes
from the column's floatingCellRenderer
property.
"use client";
import { Grid, useClientRowDataSource } from "@1771technologies/lytenyte-pro";
import "@1771technologies/lytenyte-pro/grid.css";
import type { Column } from "@1771technologies/lytenyte-pro/types";
import { bankDataSmall } from "@1771technologies/sample-data/bank-data-smaller";
import { useId } from "react";
type BankData = (typeof bankDataSmall)[number];
const columns: Column<BankData>[] = [
{ id: "age", type: "number" },
{ id: "job" },
{ id: "balance", type: "number" },
{ id: "education" },
{ id: "marital" },
{ id: "default" },
{ id: "housing" },
{ id: "loan" },
{ id: "contact" },
{ id: "day", type: "number" },
{ id: "month" },
{ id: "duration" },
{ id: "campaign" },
{ id: "pdays" },
{ id: "previous" },
{ id: "poutcome" },
{ id: "y" },
];
export default function FloatingHeader() {
const ds = useClientRowDataSource({ data: bankDataSmall });
const grid = Grid.useLyteNyte({
gridId: useId(),
rowDataSource: ds,
columns,
floatingRowEnabled: true,
columnBase: {
floatingCellRenderer: (p) => {
return (
<div
style={{
width: "100%",
height: "100%",
boxSizing: "border-box",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
paddingInline: 8,
}}
>
<button
onClick={() =>
p.grid.api.columnUpdate({
[p.column.id]: {
width: (p.column.width ?? 200) - 10,
},
})
}
>
-
</button>
Width: {p.column.width ?? 200}
<button
onClick={() =>
p.grid.api.columnUpdate({
[p.column.id]: {
width: (p.column.width ?? 200) + 10,
},
})
}
>
+
</button>
</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.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>
);
}
Set a column's floatingCellRenderer
to a React component or a string.
If you provide a string, it acts as a lookup key for components
registered in the grid's state. Use the grid's
floatingCellRenderers
property to register these components.
"use client";
import { Grid, useClientRowDataSource } from "@1771technologies/lytenyte-pro";
import "@1771technologies/lytenyte-pro/grid.css";
import type {
Column,
HeaderFloatingCellRendererParams,
} from "@1771technologies/lytenyte-pro/types";
import { bankDataSmall } from "@1771technologies/sample-data/bank-data-smaller";
import { useId } from "react";
type BankData = (typeof bankDataSmall)[number];
const columns: Column<BankData>[] = [
{ id: "age", type: "number" },
{ id: "job" },
{ id: "balance", type: "number" },
{ id: "education" },
{ id: "marital" },
{ id: "default" },
{ id: "housing" },
{ id: "loan" },
{ id: "contact" },
{ id: "day", type: "number" },
{ id: "month" },
{ id: "duration" },
{ id: "campaign" },
{ id: "pdays" },
{ id: "previous" },
{ id: "poutcome" },
{ id: "y" },
];
function WidthAdjuster(p: HeaderFloatingCellRendererParams<BankData>) {
return (
<div
style={{
width: "100%",
height: "100%",
boxSizing: "border-box",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
paddingInline: 8,
}}
>
<button
onClick={() =>
p.grid.api.columnUpdate({
[p.column.id]: {
width: (p.column.width ?? 200) - 10,
},
})
}
>
-
</button>
Width: {p.column.width ?? 200}
<button
onClick={() =>
p.grid.api.columnUpdate({
[p.column.id]: {
width: (p.column.width ?? 200) + 10,
},
})
}
>
+
</button>
</div>
);
}
export default function FloatingHeaderRegistered() {
const ds = useClientRowDataSource({ data: bankDataSmall });
const grid = Grid.useLyteNyte({
gridId: useId(),
rowDataSource: ds,
columns,
floatingRowEnabled: true,
floatingCellRenderers: { "width-adjuster": WidthAdjuster },
columnBase: {
floatingCellRenderer: "width-adjuster",
},
});
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>
);
}
We recommend registering floating cell renderers and referencing them from columns instead of providing React components directly. This practice keeps columns serializable and simplifies debugging.
Toggle the floating row by updating the grid's
floatingRowEnabled
state:
const toggleFloatingFilter = () =>
grid.state.floatingRowEnabled.set((prev) => !prev);