Skip to content

Commit c893f44

Browse files
committed
Add horizontal layout blog article
1 parent cb2cb06 commit c893f44

2 files changed

Lines changed: 202 additions & 0 deletions

File tree

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
---
2+
title: Horizontal layout for React DataGrids
3+
description: Use Infinite Table's horizontal layout to wrap rows into repeated column sets, keep grouped and tree rows readable, and make dense dashboards easier to scan.
4+
date: 2026-07-28
5+
author: radu
6+
tags: layout, performance, dashboards
7+
---
8+
9+
Most DataGrids grow in one direction: more rows mean more vertical scrolling, and more columns mean more horizontal scrolling.
10+
11+
That is usually right for record-heavy workflows, but it is not always the best use of screen space. Some dashboards have a small number of columns and many compact rows. Some operations screens need a "wallboard" view where users scan multiple row segments at once. Some tree or grouped views become easier to compare when the next batch of rows appears beside the first one, not below it.
12+
13+
Infinite Table has a documented feature for that shape: [horizontal layout](/docs/reference/infinite-table-props#wrapRowsHorizontally), powered by <PropLink name="wrapRowsHorizontally" />.
14+
15+
## What horizontal layout changes
16+
17+
When horizontal layout is disabled, the grid renders one vertical list of rows. When <PropLink name="wrapRowsHorizontally" /> is enabled, Infinite Table wraps rows into multiple side-by-side column sets.
18+
19+
If three columns are visible and ten rows fit vertically, a 25-row dataset can render as:
20+
21+
- column set 1: rows 1-10
22+
- column set 2: rows 11-20
23+
- column set 3: rows 21-25
24+
25+
Each column set repeats the same columns. Users still read rows top to bottom inside a set, but the next page of rows starts to the right.
26+
27+
```tsx
28+
<DataSource<Developer> primaryKey="id" data={dataSource}>
29+
<InfiniteTable<Developer>
30+
columns={columns}
31+
columnDefaultWidth={100}
32+
wrapRowsHorizontally
33+
/>
34+
</DataSource>
35+
```
36+
37+
That is a different layout contract from a normal grid, so it works best when every row can be understood from a small, fixed set of columns.
38+
39+
## Try it in the docs demo
40+
41+
The API docs include a compact example with a button that toggles horizontal layout. Enable it and resize the preview to see the grid create repeated column sets as vertical space runs out.
42+
43+
<Sandpack title="Horizontal layout for compact row lists" size="md" viewMode="preview">
44+
45+
<Description>
46+
47+
Toggle horizontal layout to see the same `id`, `firstName`, and `age` columns repeated across wrapped row sections. Full docs: [wrapRowsHorizontally](/docs/reference/infinite-table-props#wrapRowsHorizontally).
48+
49+
</Description>
50+
51+
```tsx live file="$DOCS/reference/horizontal-layout-example.page.tsx"
52+
53+
```
54+
55+
</Sandpack>
56+
57+
This is useful when the grid is closer to a status board than a spreadsheet:
58+
59+
- call-center queues with id, owner, and status
60+
- warehouse picking lists with SKU, aisle, and quantity
61+
- monitoring views with service, region, and health
62+
- approval queues with requester, amount, and age
63+
- incident triage boards with priority, service, and assignee
64+
65+
In those cases, showing more rows at once can matter more than preserving a single vertical stream.
66+
67+
## Label repeated column sets
68+
69+
Because the same columns repeat, it can be useful to show the column-set index in the header. Column header render functions receive `horizontalLayoutPageIndex`, which is `null` in normal layout and a zero-based number when horizontal layout is active.
70+
71+
```tsx
72+
const getColumnHeaderFor = (label: string) => {
73+
return ({ horizontalLayoutPageIndex }) => {
74+
return (
75+
<>
76+
{label}
77+
{horizontalLayoutPageIndex != null
78+
? ` (${horizontalLayoutPageIndex + 1})`
79+
: ''}
80+
</>
81+
);
82+
};
83+
};
84+
85+
const columns = {
86+
id: {
87+
field: 'id',
88+
header: getColumnHeaderFor('ID'),
89+
},
90+
firstName: {
91+
field: 'firstName',
92+
header: getColumnHeaderFor('Name'),
93+
},
94+
};
95+
```
96+
97+
The result is subtle but helpful: the user can tell whether they are reading the first, second, or third wrapped segment without losing the familiar column labels.
98+
99+
<Sandpack title="Show the column-set index in headers" size="md" viewMode="preview">
100+
101+
<Description>
102+
103+
Headers receive `horizontalLayoutPageIndex`, so each repeated column set can render a slightly different label.
104+
105+
</Description>
106+
107+
```tsx live file="$DOCS/reference/horizontal-layout-with-column-set-index-in-header-example.page.tsx"
108+
109+
```
110+
111+
</Sandpack>
112+
113+
You can use the same value in cell rendering when a wrapped segment needs different styling, separators, or helper text.
114+
115+
## Keep grouped rows readable
116+
117+
Horizontal layout becomes more interesting when the `DataSource` is grouped. A group can start in one column set and continue into the next. If the group header only appears once, the rows in the next set lose context.
118+
119+
That is what <PropLink name="repeatWrappedGroupRows" /> is for. When enabled with <PropLink name="wrapRowsHorizontally" />, Infinite Table repeats group rows at the top of a wrapped column set when the group started in a previous set.
120+
121+
```tsx
122+
<DataSource<Developer>
123+
primaryKey="id"
124+
data={dataSource}
125+
defaultGroupBy={[{ field: 'country' }, { field: 'city' }]}
126+
>
127+
<InfiniteTable<Developer>
128+
columns={columns}
129+
wrapRowsHorizontally
130+
repeatWrappedGroupRows
131+
/>
132+
</DataSource>
133+
```
134+
135+
The repeated group row acts like a sticky label for the wrapped page: users know which country or city they are still scanning.
136+
137+
<Sandpack title="Repeat wrapped group rows" size="md" viewMode="preview">
138+
139+
<Description>
140+
141+
Turn on repeated group rows to keep grouped sections readable as rows wrap into the next column set.
142+
143+
</Description>
144+
145+
```tsx live file="$DOCS/reference/horizontal-layout-repeat-wrapped-groups-example.page.tsx"
146+
147+
```
148+
149+
</Sandpack>
150+
151+
For tree data, <PropLink name="repeatWrappedGroupRows" /> can also be a function. That lets you repeat only the parent levels that carry useful context.
152+
153+
```tsx
154+
<TreeGrid
155+
columns={columns}
156+
wrapRowsHorizontally
157+
repeatWrappedGroupRows={(rowInfo) => {
158+
if (!rowInfo.isTreeNode) {
159+
return false;
160+
}
161+
162+
return rowInfo.treeNesting === 0;
163+
}}
164+
/>
165+
```
166+
167+
In a file-browser view, for example, repeating only top-level folders can keep each wrapped section understandable without duplicating every nested parent.
168+
169+
## Design rules for horizontal layout
170+
171+
Horizontal layout is intentionally advanced. It is a good fit when the content is dense, rows are compact, and users benefit from seeing more of the dataset at once.
172+
173+
Use it when:
174+
175+
- the row height is predictable
176+
- each row needs only a few columns
177+
- users scan rows more than they compare many fields across one row
178+
- the container is wide enough for multiple column sets
179+
- grouping or tree context can be repeated clearly
180+
181+
Avoid it when:
182+
183+
- columns use flexible widths, because horizontal layout expects fixed column sizing
184+
- each row has many fields that users compare left to right
185+
- the primary workflow depends on a single uninterrupted row order
186+
- the repeated headers would create more visual noise than context
187+
188+
For traditional spreadsheet-style data entry, the normal vertical layout is usually the better default. For wallboards, operations dashboards, and dense monitoring surfaces, horizontal layout can make the same data feel much more readable.
189+
190+
## Go deeper in the docs
191+
192+
- [wrapRowsHorizontally](/docs/reference/infinite-table-props#wrapRowsHorizontally) - enable horizontal layout and understand column sets
193+
- [repeatWrappedGroupRows](/docs/reference/infinite-table-props#repeatWrappedGroupRows) - keep grouped and tree rows readable when wrapping
194+
- [TreeGrid with horizontal layout](/docs/learn/tree-grid/overview#working-with-horizontal-layout) - use wrapping with hierarchical data
195+
- [Fixed and flexible column sizes](/docs/learn/columns/fixed-and-flexible-size) - choose sizing rules that work with your layout
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Tweet draft
2+
3+
New on the Infinite Table blog: horizontal layout for React DataGrids.
4+
5+
Use `wrapRowsHorizontally` to turn compact rows into side-by-side column sets, keep grouped/tree context readable, and build dense dashboards without a custom layout engine.
6+
7+
https://infinite-table.com/blog/2026/07/28/horizontal-layout-for-react-datagrids

0 commit comments

Comments
 (0)