React Spreadsheet
The React wrapper makes it easy to add powerful spreadsheet functionality to your React applications. Whether building data tables, forms, or interactive dashboards, the React integration provides all the features you need with minimal setup.
Documentation
Using the React Wrapper
Install the React wrapper:
npm install @jspreadsheet/react
Creating Your First React Spreadsheet
Create a web-based spreadsheet using the React wrapper.
import React, {useRef} from "react";
import {Spreadsheet, Worksheet, jspreadsheet} from "@jspreadsheet/react";
// Required CSS imports
import "jsuites/dist/jsuites.css";
import "jspreadsheet/dist/jspreadsheet.css";
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('YjQ5MzQxMjQ3MGY0NzViOTM1N2E5YTQxZGY5OTNkMmY5ZWI1N2NlMWE2MjU3MGI1Mjg2YTQwYzU0YTljODY0MjkyMDRiYmQyYWViZDI4YzJiMjFhMzlkNzE5MWExMzliNmExYTRiZDFlZGMxMjMyZGI2NzRiNGU3NGQ4YWMxODgsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azFPREkzTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');
export default function App() {
// Spreadsheet array of worksheets
const spreadsheet = useRef();
// Render component
return (
<Spreadsheet ref={spreadsheet} tabs={true} toolbar={true}>
<Worksheet/>
</Spreadsheet>
);
}
Note: Don't forget to include Material Icons in your HTML head for proper icon display:
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />
Direct Library Usage
Use the library directly for greater flexibility and customization.
React with Hooks
import React, { useRef, useEffect } from "react";
import jspreadsheet from "jspreadsheet";
import "jspreadsheet/dist/jspreadsheet.css";
import "jsuites/dist/jsuites.css";
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('YjQ5MzQxMjQ3MGY0NzViOTM1N2E5YTQxZGY5OTNkMmY5ZWI1N2NlMWE2MjU3MGI1Mjg2YTQwYzU0YTljODY0MjkyMDRiYmQyYWViZDI4YzJiMjFhMzlkNzE5MWExMzliNmExYTRiZDFlZGMxMjMyZGI2NzRiNGU3NGQ4YWMxODgsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azFPREkzTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');
export default function App() {
const jssRef = useRef(null);
useEffect(() => {
// Create the spreadsheet only once
if (!jssRef.current.jspreadsheet) {
jspreadsheet(jssRef.current, {
worksheets: [{
minDimensions: [10, 10]
}],
});
}
}, []);
return (<div ref={jssRef} />);
}
React Class Components
import React from "react";
import jspreadsheet from "jspreadsheet";
import "jsuites/dist/jsuites.css";
import "jspreadsheet/dist/jspreadsheet.css";
jspreadsheet.setLicense('YjQ5MzQxMjQ3MGY0NzViOTM1N2E5YTQxZGY5OTNkMmY5ZWI1N2NlMWE2MjU3MGI1Mjg2YTQwYzU0YTljODY0MjkyMDRiYmQyYWViZDI4YzJiMjFhMzlkNzE5MWExMzliNmExYTRiZDFlZGMxMjMyZGI2NzRiNGU3NGQ4YWMxODgsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azFPREkzTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');
export default class Jspreadsheet extends React.Component {
constructor(props) {
super(props);
this.options = props.options;
this.wrapper = React.createRef();
}
componentDidMount = function () {
this.worksheets = jspreadsheet(this.wrapper.current, this.options);
};
addRow = function () {
this.worksheets[0].insertRow();
};
render() {
return (
<div>
<div ref={this.wrapper}></div>
<p>
<input type="button" value="Add new row" onClick={() => this.addRow()} className="jss_object" />
</p>
</div>
);
}
}
let options = {
worksheets: [
{
minDimensions: [10, 10]
}
],
};
ReactDOM.render(<Jspreadsheet options={options} />, document.getElementById("root"));
React States
Unlike typical React components that rely on React's immutable state, Jspreadsheet Spreadsheets employs its own internal state management system. This design addresses critical performance challenges when handling massive spreadsheet data structures with thousands of interdependent cells, extensive formulas, and complex dependency chains. These challenges would otherwise lead to:
- Excessive memory usage, especially with large datasets
- Performance bottlenecks during frequent cell updates
- Unnecessary re-renders that degrade user experience
Using optimized maps and objects, the spreadsheet efficiently tracks changes, reducing memory consumption and processing overhead. This approach ensures exceptional performance, even for large or highly complex spreadsheet representations.
An example with React State:
See this React Data Grid with Spreadsheet Controls example here: https://stackblitz.com/edit/vitejs-vite-3vxek3n6
import React, { useRef, useEffect, useState } from 'react';
import jspreadsheet from 'jspreadsheet';
import 'jspreadsheet/dist/jspreadsheet.css';
import 'jsuites/dist/jsuites.css';
// Set your JSS license key (The following key only works for one day)
jspreadsheet.setLicense('YjQ5MzQxMjQ3MGY0NzViOTM1N2E5YTQxZGY5OTNkMmY5ZWI1N2NlMWE2MjU3MGI1Mjg2YTQwYzU0YTljODY0MjkyMDRiYmQyYWViZDI4YzJiMjFhMzlkNzE5MWExMzliNmExYTRiZDFlZGMxMjMyZGI2NzRiNGU3NGQ4YWMxODgsZXlKamJHbGxiblJKWkNJNklpSXNJbTVoYldVaU9pSktjM0J5WldGa2MyaGxaWFFpTENKa1lYUmxJam94TnpVNU56azFPREkzTENKa2IyMWhhVzRpT2xzaWFuTndjbVZoWkhOb1pXVjBMbU52YlNJc0ltTnZaR1Z6WVc1a1ltOTRMbWx2SWl3aWFuTm9aV3hzTG01bGRDSXNJbU56WWk1aGNIQWlMQ0p6ZEdGamEySnNhWFI2TG1sdklpd2lkMlZpWTI5dWRHRnBibVZ5TG1sdklpd2lkMlZpSWl3aWJHOWpZV3hvYjNOMElsMHNJbkJzWVc0aU9pSXpOQ0lzSW5OamIzQmxJanBiSW5ZM0lpd2lkamdpTENKMk9TSXNJbll4TUNJc0luWXhNU0lzSW1Ob1lYSjBjeUlzSW1admNtMXpJaXdpWm05eWJYVnNZU0lzSW5CaGNuTmxjaUlzSW5KbGJtUmxjaUlzSW1OdmJXMWxiblJ6SWl3aWFXMXdiM0owWlhJaUxDSmlZWElpTENKMllXeHBaR0YwYVc5dWN5SXNJbk5sWVhKamFDSXNJbkJ5YVc1MElpd2ljMmhsWlhSeklpd2lZMnhwWlc1MElpd2ljMlZ5ZG1WeUlpd2ljMmhoY0dWeklpd2labTl5YldGMElsMHNJbVJsYlc4aU9uUnlkV1Y5');
export default function App() {
const jssRef = useRef(null);
const [isInitialized, setIsInitialized] = useState(false);
const [columns, setColumns] = useState(() => {
try {
const savedColumns = localStorage.getItem('my-columns');
return savedColumns ? JSON.parse(savedColumns) : [];
} catch (error) {
console.error('Error loading columns:', error);
return [];
}
});
useEffect(() => {
if (!jssRef.current || isInitialized) return;
try {
jspreadsheet(jssRef.current, {
worksheets: [
{
minDimensions: [10, 10],
columns: columns,
},
],
onresizecolumn: (worksheet) => {
try {
setColumns(structuredClone(worksheet.options.columns));
} catch (error) {
console.error('Error updating columns:', error);
}
},
});
setIsInitialized(true);
} catch (error) {
console.error('Error initializing spreadsheet:', error);
}
}, [isInitialized, columns]);
useEffect(() => {
try {
localStorage.setItem('my-columns', JSON.stringify(columns));
} catch (error) {
console.error('Error saving columns:', error);
}
}, [columns]);
return (
<>
<div>first column width: {columns[0]?.width}</div>
<div ref={jssRef} />
</>
);
}
Library integration examples
Real-Time React Spreadsheet
Create a real-time JavaScript spreadsheet with React and TypeScript.
Interactive Demos
React Spreadsheet Examples
- React Spreadsheet Basic React spreadsheet with translations.
- React Spreadsheet Cell Editors How to create a custom data grid cell editor with React.
- Custom React Components Integrate a custom React component (Recharts) with the spreadsheet.
- React Spreadsheet as React Classes Create a basic React spreadsheet using React classes
- React Data Grid Validations How to create a data grid with cell validations
- MUI React as a Custom Editor React Calendar with MUI
- Antd React Calendar Cell Editor React Calendar with Antd
- MUI React Calendar as a Custom Editor
NextJS integration
- Online XLSX NextJS reader Create an online XLSX reader with NextJS