Styling Rows
Introduction
Section titled “Introduction”Row styling paints whole rows — a subtle zebra stripe, a red tint on the overdue row, a bold total line. You describe the styling declaratively with two options, each of which can be a static value applied to every row or a callback evaluated per row against that row’s data:
rowClass— CSS class names added to the row. They hook into your stylesheet, so the styling lives in CSS and composes with hover, selection and your design tokens.rowStyle— inline CSS applied directly to the row. Self-contained (no stylesheet needed) and highest precedence, so it always wins.
Because ZenGrid renders individual pooled cells rather than a <tr> per row (that
is what keeps 100k rows smooth), there is no row element to style. The resolved
classes and styles are instead stamped onto every cell of the row — the effect
is identical, and it stays correct as rows recycle during scroll.
How it works
Section titled “How it works”Row styling ships in @zengrid/enterprise. Build a provider with rowStyling()
and hand it to the grid through the rowStyleProvider option:
import { rowStyling } from '@zengrid/enterprise/grid';
const grid = new Zengrid(el, { rowCount, rowStyleProvider: rowStyling({ // Static: applied to every row. rowClass: 'zebra', // Callback: evaluated per row. `data` is the row record; `row` is its index. rowStyle: ({ row, data }) => data.status === 'overdue' ? { backgroundColor: '#3a1113' } : null, }), columns: [/* … */],});Each callback receives { row, data } — the row index and the row’s record — and
returns the class/style for that row, or null/undefined for no styling. Style
keys may be camelCase (backgroundColor) or kebab-case (background-color);
custom properties (--accent) pass through untouched.
interface RowStyleParams { /** Row index in display order. */ row: number; /** The row's record. */ data: unknown;}
type RowClassValue = string | string[] | null | undefined;type RowStyleValue = Record<string, string | number> | null | undefined;
interface RowStylingOptions { rowClass?: RowClassValue | ((params: RowStyleParams) => RowClassValue); rowStyle?: RowStyleValue | ((params: RowStyleParams) => RowStyleValue);}rowClass accepts a single class, an array, or a space-separated string — they’re
merged and de-duplicated. rowStyle values are stringified, so opacity: 0.6 and
fontWeight: 600 both work.
Try it live
Section titled “Try it live”Each tab styles rows a different way. Edit the callbacks — change the stripe colour, the threshold, or the class rules — and the grid re-renders.
rowStyle: ({ row }) => (…) keys off the row index. Change the stripe colour, or make the condition row % 3 to stripe every third row.
- No
<tr>— styling lands on cells. The classes/styles are applied to every cell of the row, so target.zg-cell.your-classin CSS. This is what lets row styling stay correct while rows recycle during virtualized scroll. - Precedence. Inline
rowStylewins over everything, including the theme.rowClasscomposes by CSS specificity, so.zg-cell.your-classbeats the base.zg-cellrules but still layers under selection/active states. - Keep callbacks cheap and pure. They run during rendering for each visible row (memoized per render pass). Do the heavy work up front and read a flag off the row’s data here.
- Static or callback, per option.
rowClassandrowStyleare independent — use a static string for one and a callback for the other, or mix freely.
- Styling Cells — style individual cells and values.
- Row Height — size rows to match their emphasis.
- Row Data — supply the rows you’re styling.