Grid for React
React version of this topic (compatible with React 19+). Keep the same configuration logic from JavaScript and pass it as component props.
What this topic covers: practical setup, the framework-specific API access pattern, and copy-adapt guidance for the examples in this page.
import React, { useMemo, useRef } from 'react';
import { Grid } from 'smart-webcomponents-react/grid';
import 'smart-webcomponents-react/source/styles/smart.default.css';
export default function App() {
const componentRef = useRef(null);
const componentProps = useMemo(() => ({
// Copy this topic's JavaScript configuration here.
}), []);
return <Grid ref={componentRef} {...componentProps}></Grid>;
}
Use componentRef.current for API methods in this topic.
Row ID auto-assigned and generated by the Grid
A grid row has an unique row ID. The row ID is used by the Grid as an unique identifier. It is used to get or set selection, expand a row, etc. The row IDs can be auto-generated by the Grid or assigned by the developer through the data binding.By setting the
grid.dataSource property, row IDs are auto-generated by the grid starting from 0 and incrementing by 1. For example, the first row's ID is 0, the second row's ID is 1 and so on. The row ID does not change after it is set.
If the Grid's data source is set, the rows will be generated again and so new row ids starting from 0 will be provided.
Row ID assigned by the Web Application
You can set the Row ID in the data binding by using thedataSource.id or dataSourceSettings.id properties.
Let's look at the following example:
The rows in the data source have unique ID fields - ALFKI, ANATR, ANTON, ABOUT, BERGS, BLAUS, BLONP, etc. You can assign these ID fields to the grid by setting the
id property of the dataSource or dataSourceSettings. In the case of the example: 'CustomerID'. By doing that,
you can select, expand and update rows by using the 'CustomerID' IDs rather than the auto-generated 0, 1, 2, 3, etc.
dataSource: new Smart.DataAdapter({
virtualDataSource: function (resultCallbackFunction, details) {
const that = this;
if (details.action === 'dataBind') {
fetch('https://raw.githubusercontent.com/HTMLElements/smart-webcomponents/master/sampledata/customers.json').then(response => response.json())
.then(data => {
Smart.demoServer = DemoServer(data);
const result = Smart.demoServer.getData(details);
resultCallbackFunction({
dataSource: result.data,
virtualDataSourceLength: result.length
});
});
}
else {
const result = Smart.demoServer.getData(details);
resultCallbackFunction({
dataSource: result.data,
virtualDataSourceLength: result.length
});
}
},
id: 'CustomerID',
dataFields: [
'CustomerID: string',
'CompanyName: string',
'ContactName: string',
'ContactTitle: string',
'Address: string',
'City: string',
'Country: string'
]
})
Row IDs assigned by the Web Developer
When new rows are added to the Grid, theonRowInserted callback function gets called with three parameters - indexes, rows array and getRowIdsFn(ids).
onRowInserted is called when the Grid is initialized and while you use the Grid and add new rows, it will be called again.
It is very useful for backend sync, because when the function is called, you add the new rows to the backend and after that you call the getRowIdsFn with the ids from the backend.
In case you need to use this function only after the Grid is initialized, you can use the grid.isInitialized boolean property.
Let's look at the example:
const componentProps = {
dataSourceSettings: {
dataFields: [
{ name: 'firstName', dataType: 'string' },
{ name: 'lastName', dataType: 'string' },
{ name: 'productName', map: 'product.name', dataType: 'string' },
{ name: 'quantity', map: 'product.quantity', dataType: 'number' },
{ name: 'price', map: 'product.price', dataType: 'number' },
{ name: 'total', map: 'product.total', dataType: 'number' }
]
},
onRowInserted(indexes, rows, getRowIdsFn) {
let IDs = [];
for (let i = 0; i < rows.length; i++) {
// get row data.
const data = rows[i].data;
IDs.push(data.firstName.substring(0, 3));
}
// set the ids to the Grid rows.
getRowIdsFn(IDs);
},
behavior: {
columnResizeMode: 'growAndShrink'
},
sorting: {
enabled: true
},
dataSource: [
{
firstName: 'Andrew',
lastName: 'Burke',
product: {
name: 'Ice Coffee', price: 10, quantity: 3, total: 30
}
},
{
firstName: 'Petra',
lastName: 'Williams',
product: {
name: 'Espresso', price: 7, quantity: 5, total: 35
}
},
{
firstName: 'Kevin',
lastName: 'Baker',
product: {
name: 'Frappucino', price: 6, quantity: 4, total: 24
}
}
],
columns: [
{
label: 'First Name', dataField: 'firstName'
},
{ label: 'Last Name', dataField: 'lastName' },
{ label: 'Product', dataField: 'productName' },
{
label: 'Quantity', dataField: 'quantity', cellsAlign: 'right', formatSettings: {
Intl: {
NumberFormat: {
style: 'currency',
currency: 'EUR'
}
}
}
},
{ label: 'Unit Price', dataField: 'price', cellsAlign: 'right', cellsFormat: 'c2' }
]
}
In the example, we set the row IDs to the first three letters from the row.data.firstName i.e the row IDs would be 'And', 'Pet', 'Kev'.
If you dynamically add a new row like that:
componentRef.current.addRow({
firstName: 'Nancy',
lastName: 'Johnes',
product: {
name: 'Espresso', price: 5, quantity: 4, total: 30
}
});
the onRowInserted callback would be called again.
Now, if we print out the Row ids using:
componentRef.current.forEachRow((row) => { console.log(row.id) });
the result would be 'And', 'Pet', 'Kev', 'Nan'
The row id can be accessed by using like that:
const rowID = grid.rows[0].id or const rowID = grid.getRowId(0);. You can also display it in the Grid by defining a new column with 'formatFunction'.
const componentProps = {
dataSourceSettings: {
dataFields: [
{ name: 'firstName', dataType: 'string' },
{ name: 'lastName', dataType: 'string' },
{ name: 'productName', map: 'product.name', dataType: 'string' },
{ name: 'quantity', map: 'product.quantity', dataType: 'number' },
{ name: 'price', map: 'product.price', dataType: 'number' },
{ name: 'total', map: 'product.total', dataType: 'number' }
]
},
onRowInserted(indexes, rows, getRowIdsFn) {
let IDs = [];
for (let i = 0; i < rows.length; i++) {
// get row data.
const data = rows[i].data;
IDs.push(data.firstName.substring(0, 3));
}
// set the ids to the Grid rows.
getRowIdsFn(IDs);
},
behavior: {
columnResizeMode: 'growAndShrink'
},
sorting: {
enabled: true
},
dataSource: [
{
firstName: 'Andrew',
lastName: 'Burke',
product: {
name: 'Ice Coffee', price: 10, quantity: 3, total: 30
}
},
{
firstName: 'Petra',
lastName: 'Williams',
product: {
name: 'Espresso', price: 7, quantity: 5, total: 35
}
},
{
firstName: 'Kevin',
lastName: 'Baker',
product: {
name: 'Frappucino', price: 6, quantity: 4, total: 24
}
}
],
columns: [
{
label: 'Id', dataField: 'id', formatFunction(settings) {
// set the cell's display value to the row ID.
settings.value = settings.row.id
}
},
{
label: 'First Name', dataField: 'firstName'
},
{ label: 'Last Name', dataField: 'lastName' },
{ label: 'Product', dataField: 'productName' },
{
label: 'Quantity', dataField: 'quantity', cellsAlign: 'right', formatSettings: {
Intl: {
NumberFormat: {
style: 'currency',
currency: 'EUR'
}
}
}
},
{ label: 'Unit Price', dataField: 'price', cellsAlign: 'right', cellsFormat: 'c2' }
]
}
For AI tooling
Developer Quick Reference
Topic: grid-row-id Component: Grid Framework: React
Main methods: addRow(), forEachRow()
Common config keys: dataSource, virtualDataSource, behavior, sorting, columns
Implementation Notes
Compatibility: React 19+ API access pattern: const componentRef = useRef(null) + componentRef.current.method()
Lifecycle guidance: Use useMemo for large config objects and call imperative API through componentRef.current after first render.
Common pitfalls:
- Recreating columns/dataSource objects on every render can reset component state.
- Calling API methods before ref is available causes runtime errors.
- Mixing controlled and imperative updates without sync can lead to stale UI.
Validation checklist:
- Keep config objects memoized when possible.
- Guard API calls with ref existence checks.
- Verify CSS theme import is present once per app.