ReactGrid is a powerful, flexible spreadsheet component for React that provides Excel-like functionality with cell editing, formulas, and data manipulation. It's designed to be lightweight and easy to use while offering essential spreadsheet features for building data-intensive applications. This guide walks through setting up and creating your first interactive spreadsheet using ReactGrid with React, from installation to a working implementation. This is part 7 of a series on using ReactGrid with React.
Prerequisites
Before you begin, make sure you have:
- Node.js version 14.0 or higher installed
- npm, yarn, or pnpm package manager
- A React project (version 16.8 or higher) or create-react-app setup
- Basic knowledge of React hooks (useState)
- Familiarity with JavaScript/TypeScript
Installation
Install ReactGrid using your preferred package manager:
npm install @silevis/reactgrid
Or with yarn:
yarn add @silevis/reactgrid
Or with pnpm:
pnpm add @silevis/reactgrid
After installation, your package.json should include:
{
"dependencies": {
"@silevis/reactgrid": "^7.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}
Project Setup
ReactGrid requires CSS styles to be imported. Add the styles to your main application file:
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import '@silevis/reactgrid/styles.css';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
First Example / Basic Usage
Let's create a simple spreadsheet component. Create a new file src/Spreadsheet.jsx:
// src/Spreadsheet.jsx
import React, { useState } from 'react';
import ReactGrid from '@silevis/reactgrid';
import '@silevis/reactgrid/styles.css';
function Spreadsheet() {
// Define the initial data structure
const [data, setData] = useState(() => {
const rows = [
[
{ type: 'header', text: 'Name' },
{ type: 'header', text: 'Age' },
{ type: 'header', text: 'City' }
],
[
{ type: 'text', text: 'John Doe' },
{ type: 'number', value: 25 },
{ type: 'text', text: 'New York' }
],
[
{ type: 'text', text: 'Jane Smith' },
{ type: 'number', value: 30 },
{ type: 'text', text: 'London' }
],
[
{ type: 'text', text: 'Bob Johnson' },
{ type: 'number', value: 35 },
{ type: 'text', text: 'Paris' }
]
];
return rows;
});
// Handle cell changes
const handleChanges = (changes) => {
setData((prevData) => {
const newData = [...prevData];
changes.forEach(({ rowId, columnId, newCell }) => {
newData[rowId][columnId] = newCell;
});
return newData;
});
};
return (
<div style={{ height: '400px', width: '100%' }}>
<ReactGrid
rows={data}
enableRangeSelection
enableFillHandle
enableRowSelection
onChanges={handleChanges}
/>
</div>
);
}
export default Spreadsheet;
Now, update your App.jsx to use the spreadsheet:
// src/App.jsx
import React from 'react';
import Spreadsheet from './Spreadsheet';
import './App.css';
function App() {
return (
<div className="App" style={{ padding: '20px' }}>
<h1>ReactGrid Example</h1>
<Spreadsheet />
</div>
);
}
export default App;
This creates a basic spreadsheet with three columns (Name, Age, City) and three rows of data. You can click on cells to edit them, and the data will update in real-time.
Understanding the Basics
ReactGrid uses a cell-based data structure where each cell is an object with:
- type: The cell type ('text', 'number', 'header', etc.)
- text: Text content for text cells
- value: Numeric value for number cells
- style: Optional styling properties
Key concepts:
- Rows: Array of row arrays, where each row contains cell objects
- Cell Types: Different cell types for different data (text, number, date, etc.)
- Changes Handler: Function that receives cell changes and updates the data
- Features: Enable features like range selection, fill handle, and row selection
Here's a simpler example with just text data:
// src/SimpleSpreadsheet.jsx
import React, { useState } from 'react';
import ReactGrid from '@silevis/reactgrid';
import '@silevis/reactgrid/styles.css';
function SimpleSpreadsheet() {
const [data, setData] = useState([
[
{ type: 'header', text: 'A' },
{ type: 'header', text: 'B' },
{ type: 'header', text: 'C' }
],
[
{ type: 'text', text: 'A1' },
{ type: 'text', text: 'B1' },
{ type: 'text', text: 'C1' }
],
[
{ type: 'text', text: 'A2' },
{ type: 'text', text: 'B2' },
{ type: 'text', text: 'C2' }
]
]);
const handleChanges = (changes) => {
setData((prevData) => {
const newData = [...prevData];
changes.forEach(({ rowId, columnId, newCell }) => {
newData[rowId][columnId] = newCell;
});
return newData;
});
};
return (
<div style={{ height: '300px', width: '100%' }}>
<ReactGrid rows={data} onChanges={handleChanges} />
</div>
);
}
export default SimpleSpreadsheet;
Practical Example / Building Something Real
Let's build a budget tracker spreadsheet with calculations:
// src/BudgetTracker.jsx
import React, { useState } from 'react';
import ReactGrid from '@silevis/reactgrid';
import '@silevis/reactgrid/styles.css';
function BudgetTracker() {
const [data, setData] = useState(() => {
return [
[
{ type: 'header', text: 'Category' },
{ type: 'header', text: 'Budgeted' },
{ type: 'header', text: 'Spent' },
{ type: 'header', text: 'Remaining' }
],
[
{ type: 'text', text: 'Food' },
{ type: 'number', value: 500 },
{ type: 'number', value: 320 },
{ type: 'number', value: 180, style: { backgroundColor: '#d4edda' } }
],
[
{ type: 'text', text: 'Transportation' },
{ type: 'number', value: 200 },
{ type: 'number', value: 150 },
{ type: 'number', value: 50, style: { backgroundColor: '#d4edda' } }
],
[
{ type: 'text', text: 'Entertainment' },
{ type: 'number', value: 300 },
{ type: 'number', value: 280 },
{ type: 'number', value: 20, style: { backgroundColor: '#d4edda' } }
],
[
{ type: 'text', text: 'Total', style: { fontWeight: 'bold' } },
{ type: 'number', value: 1000, style: { fontWeight: 'bold' } },
{ type: 'number', value: 750, style: { fontWeight: 'bold' } },
{ type: 'number', value: 250, style: { fontWeight: 'bold', backgroundColor: '#d4edda' } }
]
];
});
const calculateRemaining = (rowIndex) => {
if (rowIndex === 0 || rowIndex === data.length - 1) return; // Skip header and total row
const budgeted = data[rowIndex][1]?.value || 0;
const spent = data[rowIndex][2]?.value || 0;
const remaining = budgeted - spent;
setData((prevData) => {
const newData = [...prevData];
newData[rowIndex][3] = {
...newData[rowIndex][3],
value: remaining,
style: {
backgroundColor: remaining >= 0 ? '#d4edda' : '#f8d7da'
}
};
return newData;
});
};
const calculateTotals = () => {
let totalBudgeted = 0;
let totalSpent = 0;
for (let i = 1; i < data.length - 1; i++) {
totalBudgeted += data[i][1]?.value || 0;
totalSpent += data[i][2]?.value || 0;
}
const totalRemaining = totalBudgeted - totalSpent;
setData((prevData) => {
const newData = [...prevData];
const lastRow = newData.length - 1;
newData[lastRow][1] = { ...newData[lastRow][1], value: totalBudgeted };
newData[lastRow][2] = { ...newData[lastRow][2], value: totalSpent };
newData[lastRow][3] = {
...newData[lastRow][3],
value: totalRemaining,
style: {
backgroundColor: totalRemaining >= 0 ? '#d4edda' : '#f8d7da'
}
};
return newData;
});
};
const handleChanges = (changes) => {
setData((prevData) => {
const newData = prevData.map(row => [...row]);
changes.forEach(({ rowId, columnId, newCell }) => {
newData[rowId][columnId] = newCell;
});
// Recalculate remaining for changed rows
changes.forEach(({ rowId }) => {
if (rowId > 0 && rowId < newData.length - 1) {
const budgeted = newData[rowId][1]?.value || 0;
const spent = newData[rowId][2]?.value || 0;
newData[rowId][3] = {
...newData[rowId][3],
value: budgeted - spent,
style: {
backgroundColor: (budgeted - spent) >= 0 ? '#d4edda' : '#f8d7da'
}
};
}
});
// Recalculate totals
let totalBudgeted = 0;
let totalSpent = 0;
for (let i = 1; i < newData.length - 1; i++) {
totalBudgeted += newData[i][1]?.value || 0;
totalSpent += newData[i][2]?.value || 0;
}
const lastRow = newData.length - 1;
newData[lastRow][1] = { ...newData[lastRow][1], value: totalBudgeted };
newData[lastRow][2] = { ...newData[lastRow][2], value: totalSpent };
newData[lastRow][3] = {
...newData[lastRow][3],
value: totalBudgeted - totalSpent,
style: {
backgroundColor: (totalBudgeted - totalSpent) >= 0 ? '#d4edda' : '#f8d7da'
}
};
return newData;
});
};
return (
<div style={{ padding: '20px' }}>
<h2>Monthly Budget Tracker</h2>
<div style={{ height: '400px', width: '100%', border: '1px solid #ccc' }}>
<ReactGrid
rows={data}
enableRangeSelection
enableFillHandle
onChanges={handleChanges}
/>
</div>
</div>
);
}
export default BudgetTracker;
This example demonstrates:
- Header row with column titles
- Editable number cells for budget and spent amounts
- Automatic calculation of remaining amounts
- Conditional styling (green for positive, red for negative)
- Total row with sum calculations
- Real-time updates when cells are edited
Common Issues / Troubleshooting
Spreadsheet not displaying: Make sure you've imported the CSS file (
@silevis/reactgrid/styles.css). The container div must have an explicit height.Cell editing not working: Ensure you're handling the
onChangesevent and updating your state properly. The changes handler receives an array of change objects.Data structure errors: Remember that ReactGrid expects a 2D array structure (rows of cells). Each cell must be an object with at least a
typeproperty.Style not applying: Cell styles should be included in the cell object's
styleproperty. Make sure you're spreading existing styles when updating cells.Performance with large datasets: For very large spreadsheets, consider implementing virtualization or pagination. ReactGrid handles moderate-sized datasets well, but extremely large grids may need optimization.
Next Steps
Now that you have a basic understanding of ReactGrid:
- Learn about advanced cell types (date, checkbox, dropdown)
- Explore formula support and calculations
- Implement custom cell renderers
- Add data validation and formatting
- Learn about row and column operations
- Check the official repository: https://github.com/silevis/reactgrid
- Look for part 8 of this series for more advanced topics
Summary
You've successfully set up ReactGrid in your React application and created your first interactive spreadsheet. ReactGrid provides a straightforward way to build Excel-like interfaces with cell editing, calculations, and data manipulation, making it perfect for building data-intensive applications.

Top comments (0)