Row Height
LyteNyte Grid allows developers to control row height. Rows can have a fixed height, vary in height per row, or expand to fill the available viewport space.
The rowHeight property on the grid state controls how LyteNyte Grid
calculates each row’s height in pixels. This property accepts three possible values:
- Numbers: Sets all rows to a fixed height in pixels.
- Functions: Returns the height in pixels for each row. Use this option to create variable row heights.
- Fill String: A string of the form
fill:<number>. For example,fill:24instructs LyteNyte Grid to distribute the available viewport space across all rows, while enforcing a minimum height of24pxper row.
Number Row Heights
Set rowHeight to a number to give all rows a uniform height. The numeric value
represents the row height in pixels. The demo below shows fixed row heights in action.
Fixed Row Height
81 collapsed lines
1import "@1771technologies/lytenyte-pro/light-dark.css";2import "@1771technologies/lytenyte-pro/pill-manager.css";3import { Grid, useClientDataSource } from "@1771technologies/lytenyte-pro";4import {5 ExchangeCell,6 makePerfHeaderCell,7 NetworkCell,8 PercentCell,9 PercentCellPositiveNegative,10 SymbolCell,11 ToggleGroup,12 ToggleItem,13} from "./components.jsx";14import type { DEXPerformanceData } from "@1771technologies/grid-sample-data/dex-pairs-performance";15import { data } from "@1771technologies/grid-sample-data/dex-pairs-performance";16import { useState } from "react";17
18export interface GridSpec {19 readonly data: DEXPerformanceData;20}21
22const columns: Grid.Column<GridSpec>[] = [23 { id: "symbol", cellRenderer: SymbolCell, width: 250, name: "Symbol" },24 { id: "network", cellRenderer: NetworkCell, width: 220, hide: true, name: "Network" },25 { id: "exchange", cellRenderer: ExchangeCell, width: 220, hide: true, name: "Exchange" },26
27 {28 id: "change24h",29 cellRenderer: PercentCellPositiveNegative,30 headerRenderer: makePerfHeaderCell("Change", "24h"),31 name: "Change % 24h",32 type: "number,",33 },34
35 {36 id: "perf1w",37 cellRenderer: PercentCellPositiveNegative,38 headerRenderer: makePerfHeaderCell("Perf %", "1w"),39 name: "Perf % 1W",40 type: "number,",41 },42 {43 id: "perf1m",44 cellRenderer: PercentCellPositiveNegative,45 headerRenderer: makePerfHeaderCell("Perf %", "1m"),46 name: "Perf % 1M",47 type: "number,",48 },49 {50 id: "perf3m",51 cellRenderer: PercentCellPositiveNegative,52 headerRenderer: makePerfHeaderCell("Perf %", "3m"),53 name: "Perf % 3M",54 type: "number,",55 },56 {57 id: "perf6m",58 cellRenderer: PercentCellPositiveNegative,59 headerRenderer: makePerfHeaderCell("Perf %", "6m"),60 name: "Perf % 6M",61 type: "number,",62 },63 {64 id: "perfYtd",65 cellRenderer: PercentCellPositiveNegative,66 headerRenderer: makePerfHeaderCell("Perf %", "YTD"),67 name: "Perf % YTD",68 type: "number",69 },70 { id: "volatility", cellRenderer: PercentCell, name: "Volatility", type: "number" },71 {72 id: "volatility1m",73 cellRenderer: PercentCell,74 headerRenderer: makePerfHeaderCell("Volatility", "1m"),75 name: "Volatility 1M",76 type: "number",77 },78];79
80const base: Grid.ColumnBase<GridSpec> = { width: 80 };81
82export default function RowDemo() {83 const ds = useClientDataSource({ data: data });84 const [rowHeight, setRowHeight] = useState(40);85
86 return (87 <>88 <div className={"border-ln-border flex h-full items-center gap-1 text-nowrap border-b px-2 py-2"}>89 <div className={"text-light hidden text-xs font-medium md:block"}>Row Height:</div>90 <ToggleGroup91 type="single"92 value={`${rowHeight}`}93 className={"flex flex-wrap"}94 onValueChange={(c) => {95 if (!c) return;96 setRowHeight(Number.parseInt(c));97 }}98 >99 <ToggleItem value="30">Small</ToggleItem>100 <ToggleItem value="40">Medium</ToggleItem>101 <ToggleItem value="60">Large</ToggleItem>102 </ToggleGroup>103 </div>104 <div105 className="ln-grid ln-cell:text-xs ln-header:text-xs ln-header:text-ln-text-xlight"106 style={{ height: 500 }}107 >108 <Grid rowHeight={rowHeight} columns={columns} columnBase={base} rowSource={ds} />109 </div>110 </>111 );112}1import type { ClassValue } from "clsx";2import clsx from "clsx";3import { ToggleGroup as TG } from "radix-ui";4import { twMerge } from "tailwind-merge";5import { exchanges, networks, symbols } from "@1771technologies/grid-sample-data/dex-pairs-performance";6
7export function tw(...c: ClassValue[]) {8 return twMerge(clsx(...c));9}10import type { Grid } from "@1771technologies/lytenyte-pro";11import type { GridSpec } from "./demo";12
13export function SymbolCell({ api, row }: Grid.T.CellRendererParams<GridSpec>) {14 if (!api.rowIsLeaf(row) || !row.data) return null;15
16 const ticker = row.data.symbolTicker;17 const symbol = row.data.symbol;18 const image = symbols[row.data.symbolTicker];19
20 return (21 <div className="grid grid-cols-[20px_auto_auto] items-center gap-1.5">22 <div>23 <img24 src={image}25 alt={`Logo for symbol ${symbol}`}26 className="h-full w-full overflow-hidden rounded-full"27 />28 </div>29 <div className="bg-ln-gray-20 text-ln-text-dark flex h-fit items-center justify-center rounded-lg px-2 py-px text-[10px]">30 {ticker}31 </div>32 <div className="w-full overflow-hidden text-ellipsis">{symbol.split("/")[0]}</div>33 </div>34 );35}36
37export function NetworkCell({ api, row }: Grid.T.CellRendererParams<GridSpec>) {38 if (!api.rowIsLeaf(row) || !row.data) return null;39
40 const name = row.data.network;41 const image = networks[name];42
43 return (44 <div className="grid grid-cols-[20px_1fr] items-center gap-1.5">45 <div>46 <img47 src={image}48 alt={`Logo for network ${name}`}49 className="h-full w-full overflow-hidden rounded-full"50 />51 </div>52 <div className="w-full overflow-hidden text-ellipsis">{name}</div>53 </div>54 );55}56
57export function ExchangeCell({ api, row }: Grid.T.CellRendererParams<GridSpec>) {58 if (!api.rowIsLeaf(row) || !row.data) return null;59
60 const name = row.data.exchange;61 const image = exchanges[name];62
63 return (64 <div className="grid grid-cols-[20px_1fr] items-center gap-1.5">65 <div>66 <img67 src={image}68 alt={`Logo for exchange ${name}`}69 className="h-full w-full overflow-hidden rounded-full"70 />71 </div>72 <div className="w-full overflow-hidden text-ellipsis">{name}</div>73 </div>74 );75}76
77export function PercentCellPositiveNegative({ api, column, row }: Grid.T.CellRendererParams<GridSpec>) {78 if (!api.rowIsLeaf(row) || !row.data) return null;79
80 const field = api.columnField(column, row);81
82 if (typeof field !== "number") return "-";83
84 const value = (field > 0 ? "+" : "") + (field * 100).toFixed(2) + "%";85
86 return (87 <div88 className={tw(89 "h-ful flex w-full items-center justify-end tabular-nums",90 field < 0 ? "text-red-600 dark:text-red-300" : "text-green-600 dark:text-green-300",91 )}92 >93 {value}94 </div>95 );96}97
98export function PercentCell({ api, column, row }: Grid.T.CellRendererParams<GridSpec>) {99 if (!api.rowIsLeaf(row) || !row.data) return null;100
101 const field = api.columnField(column, row);102
103 if (typeof field !== "number") return "-";104
105 const value = (field > 0 ? "+" : "") + (field * 100).toFixed(2) + "%";106
107 return <div className="h-ful flex w-full items-center justify-end tabular-nums">{value}</div>;108}109
110export const makePerfHeaderCell = (name: string, subname: string) => {111 return (_: Grid.T.HeaderParams<GridSpec>) => {112 return (113 <div className="flex h-full w-full flex-col items-end justify-center tabular-nums">114 <div>{name}</div>115 <div className="text-ln-text-light font-mono uppercase">{subname}</div>116 </div>117 );118 };119};120
121export function ToggleGroup(props: Parameters<typeof TG.Root>[0]) {122 return (123 <TG.Root124 {...props}125 className={tw("bg-ln-gray-20 flex items-center gap-2 rounded-xl px-2 py-1", props.className)}126 ></TG.Root>127 );128}129
130export function ToggleItem(props: Parameters<typeof TG.Item>[0]) {131 return (132 <TG.Item133 {...props}134 className={tw(135 "text-ln-text flex cursor-pointer items-center justify-center px-2 py-1 text-xs font-bold outline-none focus:outline-none",136 "data-[state=on]:text-ln-text-dark data-[state=on]:bg-linear-to-b from-ln-gray-02 to-ln-gray-05 data-[state=on]:rounded-md",137 props.className,138 )}139 ></TG.Item>140 );141}Variable Row Height
LyteNyte Grid supports variable row heights through a function callback. This function must return a number representing the row height in pixels, and the returned value may differ per row.
LyteNyte Grid calls this function for every row during layout, so performance is critical. Keep the implementation simple and avoid expensive calculations inside the callback.
The demo below illustrates variable row heights in practice.
Variable Row Height
78 collapsed lines
1import "@1771technologies/lytenyte-pro/light-dark.css";2import "@1771technologies/lytenyte-pro/pill-manager.css";3import { Grid, useClientDataSource } from "@1771technologies/lytenyte-pro";4import {5 ExchangeCell,6 makePerfHeaderCell,7 NetworkCell,8 PercentCell,9 PercentCellPositiveNegative,10 SymbolCell,11} from "./components.jsx";12import type { DEXPerformanceData } from "@1771technologies/grid-sample-data/dex-pairs-performance";13import { data } from "@1771technologies/grid-sample-data/dex-pairs-performance";14
15export interface GridSpec {16 readonly data: DEXPerformanceData;17}18
19const columns: Grid.Column<GridSpec>[] = [20 { id: "symbol", cellRenderer: SymbolCell, width: 250, name: "Symbol" },21 { id: "network", cellRenderer: NetworkCell, width: 220, hide: true, name: "Network" },22 { id: "exchange", cellRenderer: ExchangeCell, width: 220, hide: true, name: "Exchange" },23
24 {25 id: "change24h",26 cellRenderer: PercentCellPositiveNegative,27 headerRenderer: makePerfHeaderCell("Change", "24h"),28 name: "Change % 24h",29 type: "number,",30 },31
32 {33 id: "perf1w",34 cellRenderer: PercentCellPositiveNegative,35 headerRenderer: makePerfHeaderCell("Perf %", "1w"),36 name: "Perf % 1W",37 type: "number,",38 },39 {40 id: "perf1m",41 cellRenderer: PercentCellPositiveNegative,42 headerRenderer: makePerfHeaderCell("Perf %", "1m"),43 name: "Perf % 1M",44 type: "number,",45 },46 {47 id: "perf3m",48 cellRenderer: PercentCellPositiveNegative,49 headerRenderer: makePerfHeaderCell("Perf %", "3m"),50 name: "Perf % 3M",51 type: "number,",52 },53 {54 id: "perf6m",55 cellRenderer: PercentCellPositiveNegative,56 headerRenderer: makePerfHeaderCell("Perf %", "6m"),57 name: "Perf % 6M",58 type: "number,",59 },60 {61 id: "perfYtd",62 cellRenderer: PercentCellPositiveNegative,63 headerRenderer: makePerfHeaderCell("Perf %", "YTD"),64 name: "Perf % YTD",65 type: "number",66 },67 { id: "volatility", cellRenderer: PercentCell, name: "Volatility", type: "number" },68 {69 id: "volatility1m",70 cellRenderer: PercentCell,71 headerRenderer: makePerfHeaderCell("Volatility", "1m"),72 name: "Volatility 1M",73 type: "number",74 },75];76
77const base: Grid.ColumnBase<GridSpec> = { width: 80 };78
79
80const rowHeight = (i: number) => [30, 50, 80, 120][i % 4];81
82export default function RowDemo() {83 const ds = useClientDataSource({ data: data });84
85 return (86 <div87 className="ln-grid ln-cell:text-xs ln-header:text-xs ln-header:text-ln-text-xlight"88 style={{ height: 500 }}89 >90 <Grid rowHeight={rowHeight} columns={columns} columnBase={base} rowSource={ds} />91 </div>92 );93}1import type { ClassValue } from "clsx";2import clsx from "clsx";3import { twMerge } from "tailwind-merge";4import { exchanges, networks, symbols } from "@1771technologies/grid-sample-data/dex-pairs-performance";5
6export function tw(...c: ClassValue[]) {7 return twMerge(clsx(...c));8}9import type { Grid } from "@1771technologies/lytenyte-pro";10import type { GridSpec } from "./demo";11
12export function SymbolCell({ api, row }: Grid.T.CellRendererParams<GridSpec>) {13 if (!api.rowIsLeaf(row) || !row.data) return null;14
15 const ticker = row.data.symbolTicker;16 const symbol = row.data.symbol;17 const image = symbols[row.data.symbolTicker];18
19 return (20 <div className="grid grid-cols-[20px_auto_auto] items-center gap-1.5">21 <div>22 <img23 src={image}24 alt={`Logo for symbol ${symbol}`}25 className="h-full w-full overflow-hidden rounded-full"26 />27 </div>28 <div className="bg-ln-gray-20 text-ln-text-dark flex h-fit items-center justify-center rounded-lg px-2 py-px text-[10px]">29 {ticker}30 </div>31 <div className="w-full overflow-hidden text-ellipsis">{symbol.split("/")[0]}</div>32 </div>33 );34}35
36export function NetworkCell({ api, row }: Grid.T.CellRendererParams<GridSpec>) {37 if (!api.rowIsLeaf(row) || !row.data) return null;38
39 const name = row.data.network;40 const image = networks[name];41
42 return (43 <div className="grid grid-cols-[20px_1fr] items-center gap-1.5">44 <div>45 <img46 src={image}47 alt={`Logo for network ${name}`}48 className="h-full w-full overflow-hidden rounded-full"49 />50 </div>51 <div className="w-full overflow-hidden text-ellipsis">{name}</div>52 </div>53 );54}55
56export function ExchangeCell({ api, row }: Grid.T.CellRendererParams<GridSpec>) {57 if (!api.rowIsLeaf(row) || !row.data) return null;58
59 const name = row.data.exchange;60 const image = exchanges[name];61
62 return (63 <div className="grid grid-cols-[20px_1fr] items-center gap-1.5">64 <div>65 <img66 src={image}67 alt={`Logo for exchange ${name}`}68 className="h-full w-full overflow-hidden rounded-full"69 />70 </div>71 <div className="w-full overflow-hidden text-ellipsis">{name}</div>72 </div>73 );74}75
76export function PercentCellPositiveNegative({ api, column, row }: Grid.T.CellRendererParams<GridSpec>) {77 if (!api.rowIsLeaf(row) || !row.data) return null;78
79 const field = api.columnField(column, row);80
81 if (typeof field !== "number") return "-";82
83 const value = (field > 0 ? "+" : "") + (field * 100).toFixed(2) + "%";84
85 return (86 <div87 className={tw(88 "h-ful flex w-full items-center justify-end tabular-nums",89 field < 0 ? "text-red-600 dark:text-red-300" : "text-green-600 dark:text-green-300",90 )}91 >92 {value}93 </div>94 );95}96
97export function PercentCell({ api, column, row }: Grid.T.CellRendererParams<GridSpec>) {98 if (!api.rowIsLeaf(row) || !row.data) return null;99
100 const field = api.columnField(column, row);101
102 if (typeof field !== "number") return "-";103
104 const value = (field > 0 ? "+" : "") + (field * 100).toFixed(2) + "%";105
106 return <div className="h-ful flex w-full items-center justify-end tabular-nums">{value}</div>;107}108
109export const makePerfHeaderCell = (name: string, subname: string) => {110 return (_: Grid.T.HeaderParams<GridSpec>) => {111 return (112 <div className="flex h-full w-full flex-col items-end justify-center tabular-nums">113 <div>{name}</div>114 <div className="text-ln-text-light font-mono uppercase">{subname}</div>115 </div>116 );117 };118};In this example, the row height cycles through a predefined set of values. While this demo uses a simple pattern, your own logic can be as complex as needed, as long as it remains performant.
1const rowHeight = (i: number) => [30, 50, 80, 120][i % 4];Fill Row Height
Use the fill row height syntax "fill:<n>" to make rows expand and fill
the available viewport space, where n is the minimum row height in pixels.
LyteNyte Grid assigns each row its minimum height, calculates the remaining available space, and then distributes that space evenly across all rows. This approach works well when the grid displays only a small number of rows and you want them to occupy the full viewport height.
Fill Row Height
28 collapsed lines
1import "@1771technologies/lytenyte-pro/light-dark.css";2import type { OrderData } from "@1771technologies/grid-sample-data/orders";3import { data } from "@1771technologies/grid-sample-data/orders";4import {5 AvatarCell,6 EmailCell,7 IdCell,8 PaymentMethodCell,9 PriceCell,10 ProductCell,11 PurchaseDateCell,12} from "./components.jsx";13import { useClientDataSource, Grid } from "@1771technologies/lytenyte-pro";14
15const columns: Grid.Column<GridSpec>[] = [16 { id: "id", width: 60, widthMin: 60, cellRenderer: IdCell, name: "ID" },17 { id: "product", cellRenderer: ProductCell, width: 200, name: "Product" },18 { id: "price", type: "number", cellRenderer: PriceCell, width: 100, name: "Price" },19 { id: "customer", cellRenderer: AvatarCell, width: 180, name: "Customer" },20 { id: "purchaseDate", cellRenderer: PurchaseDateCell, name: "Purchase Date", width: 130 },21 { id: "paymentMethod", cellRenderer: PaymentMethodCell, name: "Payment Method", width: 150 },22 { id: "email", cellRenderer: EmailCell, width: 220, name: "Email" },23];24
25export interface GridSpec {26 readonly data: OrderData;27}28
29export default function RowDemo() {30 const ds = useClientDataSource({ data: data.slice(0, 8) });31
32 return (33 <>34 <div className={"ln-grid"} style={{ height: 500 }}>35 <Grid rowHeight="fill:50" columns={columns} rowSource={ds} />36 </div>37 </>38 );39}1import { format } from "date-fns";2import { type JSX, type ReactNode } from "react";3import type { Grid } from "@1771technologies/lytenyte-pro";4import type { GridSpec } from "./demo.jsx";5
6export function ProductCell({ api, row }: Grid.T.CellRendererParams<GridSpec>) {7 if (!api.rowIsLeaf(row) || !row.data) return;8
9 const url = row.data?.productThumbnail;10 const title = row.data.product;11 const desc = row.data.productDescription;12
13 return (14 <div className="flex h-full w-full items-center gap-2">15 <img className="border-ln-border-strong h-7 w-7 rounded-lg border" src={url} alt={title + desc} />16 <div className="text-ln-text-dark flex flex-col gap-0.5">17 <div className="font-semibold">{title}</div>18 <div className="text-ln-text-light text-xs">{desc}</div>19 </div>20 </div>21 );22}23
24export function AvatarCell({ api, row }: Grid.T.CellRendererParams<GridSpec>) {25 if (!api.rowIsLeaf(row) || !row.data) return;26
27 const url = row.data?.customerAvatar;28
29 const name = row.data.customer;30
31 return (32 <div className="flex h-full w-full items-center gap-2">33 <img className="border-ln-border-strong h-7 w-7 rounded-full border" src={url} alt={name} />34 <div className="text-ln-text-dark flex flex-col gap-0.5">35 <div>{name}</div>36 </div>37 </div>38 );39}40
41const formatter = new Intl.NumberFormat("en-Us", {42 minimumFractionDigits: 2,43 maximumFractionDigits: 2,44});45export function PriceCell({ api, row }: Grid.T.CellRendererParams<GridSpec>) {46 if (!api.rowIsLeaf(row) || !row.data) return;47
48 const price = formatter.format(row.data.price);49 const [dollars, cents] = price.split(".");50
51 return (52 <div className="flex h-full w-full items-center justify-end">53 <div className="flex items-baseline tabular-nums">54 <span className="text-ln-text font-semibold">${dollars}</span>.55 <span className="relative text-xs">{cents}</span>56 </div>57 </div>58 );59}60
61export function PurchaseDateCell({ api, row }: Grid.T.CellRendererParams<GridSpec>) {62 if (!api.rowIsLeaf(row) || !row.data) return;63
64 const formattedDate = format(row.data.purchaseDate, "dd MMM, yyyy");65
66 return <div className="flex h-full w-full items-center">{formattedDate}</div>;67}68export function IdCell({ api, row }: Grid.T.CellRendererParams<GridSpec>) {69 if (!api.rowIsLeaf(row) || !row.data) return;70
71 return <div className="text-xs tabular-nums">{row.data.id}</div>;72}73
74export function PaymentMethodCell({ api, row }: Grid.T.CellRendererParams<GridSpec>) {75 if (!api.rowIsLeaf(row) || !row.data) return;76
77 const cardNumber = row.data.cardNumber;78 const provider = row.data.paymentMethod;79
80 let Logo: ReactNode = null;81 if (provider === "Visa") Logo = <VisaLogo className="w-6" />;82 if (provider === "Mastercard") Logo = <MastercardLogo className="w-6" />;83
84 return (85 <div className="flex h-full w-full items-center gap-2">86 <div className="flex w-7 items-center justify-center">{Logo}</div>87 <div className="flex items-center gap-px">88 <div className="bg-ln-gray-40 size-2 rounded-full"></div>89 <div className="bg-ln-gray-40 size-2 rounded-full"></div>90 <div className="bg-ln-gray-40 size-2 rounded-full"></div>91 <div className="bg-ln-gray-40 size-2 rounded-full"></div>92 </div>93 <div className="tabular-nums">{cardNumber}</div>94 </div>95 );96}97
98export function EmailCell({ api, row }: Grid.T.CellRendererParams<GridSpec>) {99 if (!api.rowIsLeaf(row) || !row.data) return;100
101 return <div className="text-ln-primary-50 flex h-full w-full items-center">{row.data.email}</div>;102}103
104const VisaLogo = (props: JSX.IntrinsicElements["svg"]) => (105 <svg xmlns="http://www.w3.org/2000/svg" width={2500} height={812} viewBox="0.5 0.5 999 323.684" {...props}>106 <path107 fill="#1434cb"108 d="M651.185.5c-70.933 0-134.322 36.766-134.322 104.694 0 77.9 112.423 83.28 112.423 122.415 0 16.478-18.884 31.229-51.137 31.229-45.773 0-79.984-20.611-79.984-20.611l-14.638 68.547s39.41 17.41 91.734 17.41c77.552 0 138.576-38.572 138.576-107.66 0-82.316-112.89-87.537-112.89-123.86 0-12.91 15.501-27.053 47.662-27.053 36.286 0 65.892 14.99 65.892 14.99l14.326-66.204S696.614.5 651.185.5zM2.218 5.497.5 15.49s29.842 5.461 56.719 16.356c34.606 12.492 37.072 19.765 42.9 42.353l63.51 244.832h85.138L379.927 5.497h-84.942L210.707 218.67l-34.39-180.696c-3.154-20.68-19.13-32.477-38.685-32.477H2.218zm411.865 0L347.449 319.03h80.999l66.4-313.534h-80.765zm451.759 0c-19.532 0-29.88 10.457-37.474 28.73L709.699 319.03h84.942l16.434-47.468h103.483l9.994 47.468H999.5L934.115 5.497h-68.273zm11.047 84.707 25.178 117.653h-67.454z"109 />110 </svg>111);112
113const MastercardLogo = (props: JSX.IntrinsicElements["svg"]) => (114 <svg115 xmlns="http://www.w3.org/2000/svg"116 width={2500}117 height={1524}118 viewBox="55.2 38.3 464.5 287.8"119 {...props}120 >121 <path122 fill="#f79f1a"123 d="M519.7 182.2c0 79.5-64.3 143.9-143.6 143.9s-143.6-64.4-143.6-143.9S296.7 38.3 376 38.3s143.7 64.4 143.7 143.9z"124 />125 <path126 fill="#ea001b"127 d="M342.4 182.2c0 79.5-64.3 143.9-143.6 143.9S55.2 261.7 55.2 182.2 119.5 38.3 198.8 38.3s143.6 64.4 143.6 143.9z"128 />129 <path130 fill="#ff5f01"131 d="M287.4 68.9c-33.5 26.3-55 67.3-55 113.3s21.5 87 55 113.3c33.5-26.3 55-67.3 55-113.3s-21.5-86.9-55-113.3z"132 />133 </svg>134);Info
When using fill row heights, if the combined minimum height of all rows exceeds the viewport height, the grid cannot distribute additional space. In this case, each row renders at exactly its minimum height, behaving the same as fixed-height rows.
Next Steps
- Row Pinning: Freeze rows at the top or bottom of the viewport.
- Row Full Width: Create rows that span the full width of the viewport.
- Row Selection: Select single or multiple rows.
