Customizing Indentation and Icons with a TreeGrid in React
Background:
There may be times when the default styling does not meet your applications needs, and you may want to adjust the style of your columns so you can more easily understand the hierarchy. This can be achieved with Wijmo by following this article.
Steps to Complete:
- Provide hierarchical data
- Adjust indentation with the formatItem event
- Apply custom icons with CSS
Getting Started:
Provide hierarchical data
FlexGrid becomes a TreeGrid automatically when you supply nested data using the property defined in childItemsPath.
const data = [
{
name: 'Electronics',
sales: 120000,
children: [
{ name: 'Phones', sales: 55000 },
{ name: 'Laptops', sales: 65000 }
]
},
{
name: 'Home',
sales: 95000,
children: [
{ name: 'Furniture', sales: 50000 },
{ name: 'Kitchen', sales: 45000 }
]
}
];
Adjust indentation with the formatItem event
This event fires whenever FlexGrid renders a cell. You use it to modify padding based on the row’s hierarchy level.
const onFormatItem = (s, e) => {
const col = e.getColumn();
const row = e.getRow();
if (col.binding === 'name') {
let padding = (row.level || 0) * 14;
if (!row.hasChildren) {
padding += 21;
}
e.cell.style.paddingLeft = `${padding}px`;
}
};
Apply custom icons with CSS
Replacing the default Wijmo glyphs is done entirely with CSS.
.wj-flexgrid .wj-cell:has(.wj-glyph-down-right) {
display: flex;
}
.wj-flexgrid .wj-cell:has(.wj-glyph-right) {
display: flex;
align-items: center;
}
.wj-glyph-down-right {
background-image: url('data:image/png;base64,…');
background-repeat: no-repeat;
width: 20px;
height: 20px;
}
.wj-glyph-right {
background-image: url('data:image/png;base64,…');
background-repeat: no-repeat;
width: 20px;
height: 20px;
}
You can of course accomplish more of the styling through the formatItem event if you prefer, this is just one way of adding customization.
I hope you found this article helpful. I will include the full code files at the end of this article.
Happy coding!
Files for reference:
App.jsx
import React, { useRef } from 'react';
import { FlexGrid, FlexGridColumn } from '@mescius/wijmo.react.grid';
import './App.css';
export default function App() {
const gridRef = useRef(null);
const data = [
{
name: 'Electronics',
sales: 120000,
children: [
{ name: 'Phones', sales: 55000 },
{ name: 'Laptops', sales: 65000 }
]
},
{
name: 'Home',
sales: 95000,
children: [
{ name: 'Furniture', sales: 50000 },
{ name: 'Kitchen', sales: 45000 }
]
}
];
const onFormatItem = (s, e) => {
const col = e.getColumn();
const row = e.getRow();
if (col.binding === 'name') {
let padding = (row.level || 0) * 14;
if (!row.hasChildren) {
padding += 21;
}
e.cell.style.paddingLeft = `${padding}px`;
}
};
return (
<div style={{ padding: '20px' }}>
<h2>React TreeGrid with Custom Indentation & Icons</h2>
<FlexGrid
ref={gridRef}
itemsSource={data}
childItemsPath="children"
autoGenerateColumns={false}
formatItem={onFormatItem}
>
<FlexGridColumn binding="name" header="Name" />
<FlexGridColumn binding="sales" header="Sales" />
</FlexGrid>
</div>
);
}
App.css
/* Ensure flex behavior when a cell contains a custom tree glyph */
.wj-flexgrid .wj-cell:has(.wj-glyph-down-right) {
display: flex;
}
.wj-flexgrid .wj-cell:has(.wj-glyph-right) {
display: flex;
align-items: center;
}
/* Custom expand icon */
.wj-glyph-down-right {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAABm0lEQVR4nL2Ty0rDQBSGo0+gvoAbO9PW9gGE6tbqS4jgFQVBH6A7qy/QRZLqRlwI7UxAtK1IN2qrdCm+gVovoLtaTXrkjJcmmcSmgg4cCJPJl//M/x9F+c+VUlK9ejgX00JsEgufca9rkBbdG9Ao39AIu9UpB0cRfqNTls7E9/sDwfQQH9Mov5dAct2pITbaGUZ4MwBMFJ5V/aCfbQZRJinNeLWvU775Cxh8FEs7YOic24BsxPAFSO8Iqzvc36Isbj+wM3IID5dPUJyvSLDCzBk8Xj3DbqLg2FcjxvA3MEvyE/aXpcUqtMwWmA0TDqZP2/vzVTCbFlhmC0oLVZdBRrJtCDGSbiXHKxfiQwGdOoHiXEXA8EfltZqkXKVsvG1IOBfzuqvyak0A3homWK+WqKPlc897Ve0tixETEyAf/FIqYEveMI2wa1CgxxUblvZzFZUWZmWDbC6vSznEcGJIu84gYfXtQdbnOS04Rt2Mnk7ZS5bkE54wOzSQUsLqHWGKo32W9jIKDcA7823zp4XuYxww+KKGeFRy86/XO/G5aIX/VUs6AAAAAElFTkSuQmCC');
background-repeat: no-repeat;
width: 20px;
height: 20px;
border: none !important;
}
/* Custom collapse icon */
.wj-glyph-right {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAABZ0lEQVR4nNWTQS8DQRTHh4+BIzMiLkgEH8SBL+AblEX6PcwQm27dZGbbTSUOraYXB9yEUAQHDq20iYpD9cnbEnZ3Ztpr/8lL9vD2l/f+83+EDKx2xg/HOFObnMmyYPIe6+fb2Z/Ij/YNAgJDnMptztSHYAq0RWULwdhLbEqT9LCg6sAIihWn0rNCcbL4T8FqBdy5wAKWjs2zyJq55TK0P7/g9aIO7qwBSmVL66lgaivevDedg8fSC6BsUD7pbyTXDV8w2RyBnhugVJU0/qkHk08R6FkN3JkolDN1p1kZs6YH7k75UA2eQ2DtsgGZ+UK8p6qb8MQEu/WfQlj9qgHeQkEXn6JuQscKu25qYaL70qkEEJ++ewF/jfmVCnTaHXi7aYK3eGQK97tgakSbRd2Ux2unkF3Sw4zT/QrPSFCV7ff0BJOZnvccQnHS2PqJNalM9YSRf0JP8QIwtJizsKgscqrWjZ4NhL4BeNMpwMOfx2cAAAAASUVORK5CYII=');
background-repeat: no-repeat;
width: 20px;
height: 20px;
border: none !important;
}
