npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-excel-table

v1.2.1

Published

Excel-like editable data table for React with virtualization, keyboard navigation, and Excel import/export

Readme

react-excel-table

A powerful, secure, and customizable Excel-like data table for React.

npm version TypeScript License: MIT

Features

  • Minimal Setup - Only data and columns required
  • Full Keyboard Navigation - Arrow keys, Tab, Enter, Escape
  • Virtualized - Handles 10,000+ rows
  • Secure by Default - Protection against XSS and formula injection
  • Fully Customizable - CSS variables for theming
  • TypeScript First - Complete type safety
  • Tree-shakeable - Import only what you need

Installation

npm install react-excel-table

Peer dependencies:

npm install react react-dom @tanstack/react-table react-window

Quick Start

import { ExcelTable } from 'react-excel-table';
import 'react-excel-table/styles';

const data = [
  { id: '1', name: 'John', email: '[email protected]', amount: 1500 },
  { id: '2', name: 'Jane', email: '[email protected]', amount: 2300 },
];

const columns = [
  { accessorKey: 'name', header: 'Name' },
  { accessorKey: 'email', header: 'Email' },
  { accessorKey: 'amount', header: 'Amount', dataType: 'currency' },
];

function App() {
  return <ExcelTable data={data} columns={columns} />;
}

That's it. You have a working editable table.


Examples

Save Changes

<ExcelTable
  data={data}
  columns={columns}
  onSave={async (data, modifiedCells) => {
    // modifiedCells = { rowId: { columnId: newValue } }
    await api.save(modifiedCells);
    return { newlyCreated: [], updatedData: data };
  }}
/>

Add and Delete Rows

<ExcelTable
  data={data}
  columns={columns}
  onAddRow={() => ({
    id: crypto.randomUUID(),
    name: '',
    email: '',
    amount: 0,
  })}
  onDelete={async (ids) => {
    await api.delete(ids);
    return { totalDeleted: ids.length, total: data.length };
  }}
/>

Read-Only Rows

<ExcelTable
  data={data}
  columns={columns}
  isReadOnlyRow={(row) => row.status === 'locked'}
/>

Read-Only Columns

const columns = [
  { accessorKey: 'id', header: 'ID', editable: false },
  { accessorKey: 'name', header: 'Name' }, // editable by default
  { accessorKey: 'total', header: 'Total', dataType: 'currency', editable: false },
];

Track Changes in Real-Time

<ExcelTable
  data={data}
  columns={columns}
  onModifiedCellsChange={(cells) => {
    console.log('Modified:', cells);
  }}
/>

Loading State

<ExcelTable data={data} columns={columns} loading={isLoading} />

Column Types

| Type | Usage | Example | |------|-------|---------| | string | Text input (default) | Name, Email | | number | Numeric input | Quantity | | currency | Formatted money | Price, Total | | date | Date picker | Created, Due Date | | select | Dropdown | Status, Category | | boolean | Checkbox | Active, Verified |

Column Configuration

{
  // Required
  accessorKey: 'fieldName',
  header: 'Display Name',

  // Optional
  dataType: 'string',      // 'string' | 'number' | 'currency' | 'date' | 'select' | 'boolean'
  editable: true,          // Allow editing
  sortable: false,         // Enable sorting
  size: 140,               // Fixed width (px)
  autosize: false,         // Auto-calculate width
  minWidth: 80,            // Minimum width
  maxWidth: 400,           // Maximum width
  dateFormat: 'yyyy-MM-dd', // For date columns
  meta: { ... },           // Extended options
}

Select Column

{
  accessorKey: 'status',
  header: 'Status',
  dataType: 'select',
  meta: {
    selectOptions: [
      { label: 'Pending', value: 'pending' },
      { label: 'Approved', value: 'approved' },
      { label: 'Rejected', value: 'rejected' },
    ],
  },
}

Dynamic Select Options

{
  accessorKey: 'category',
  header: 'Category',
  dataType: 'select',
  meta: {
    getDynamicSelectOptions: (row) => {
      return row.type === 'income' ? incomeOptions : expenseOptions;
    },
    onAddNew: () => openModal(),
  },
}

Styling

CSS Variables

:root {
  /* Colors */
  --excel-primary: #30867B;
  --excel-primary-hover: #2D9084;
  --excel-danger: #ef4444;
  --excel-success: #22c55e;

  /* Cell States */
  --excel-cell-modified-bg: #2D9084;
  --excel-cell-modified-text: #ffffff;
  --excel-cell-readonly-bg: #f3f4f6;
  --excel-cell-hover-bg: #f9fafb;

  /* Layout */
  --excel-row-height: 40px;
  --excel-header-height: 44px;
  --excel-border-color: #e5e7eb;
  --excel-border-radius: 0.375rem;

  /* Typography */
  --excel-font-family: system-ui, sans-serif;
  --excel-font-size: 14px;
}

Built-in Variants

// Compact
<ExcelTable className="excel-table--compact" ... />

// Comfortable (spacious)
<ExcelTable className="excel-table--comfortable" ... />

// Bordered cells
<ExcelTable className="excel-table--bordered" ... />

// Striped rows
<ExcelTable className="excel-table--striped" ... />

// No borders
<ExcelTable className="excel-table--borderless" ... />

Color Themes

<ExcelTable className="excel-theme--blue" ... />
<ExcelTable className="excel-theme--purple" ... />
<ExcelTable className="excel-theme--orange" ... />
<ExcelTable className="excel-theme--rose" ... />

Dark Mode

[data-theme="dark"] {
  --excel-primary: #4ade80;
  --excel-cell-modified-bg: #166534;
  --excel-cell-readonly-bg: #1f2937;
  --excel-border-color: #374151;
  --excel-cell-hover-bg: #1f2937;
}

Tailwind CSS

// tailwind.config.js
import { excelTablePreset } from 'react-excel-table/styles';

export default {
  presets: [excelTablePreset],
}

Global Configuration

Set defaults for all tables:

import { ExcelTableProvider, LOCALE_PRESETS } from 'react-excel-table';

function App() {
  return (
    <ExcelTableProvider
      locale={{
        ...LOCALE_PRESETS['es-MX'],
        currency: 'MXN',
        dateFormat: 'dd/MM/yyyy',
      }}
    >
      <YourApp />
    </ExcelTableProvider>
  );
}

Available Presets

| Preset | Currency | Date Format | |--------|----------|-------------| | en-US | USD | MM/dd/yyyy | | es-MX | MXN | dd/MM/yyyy | | es-ES | EUR | dd/MM/yyyy | | de-DE | EUR | dd.MM.yyyy | | fr-FR | EUR | dd/MM/yyyy | | pt-BR | BRL | dd/MM/yyyy | | ja-JP | JPY | yyyy/MM/dd |


Import Plugin

Import CSV/Excel files with automatic security sanitization.

npm install papaparse
import { useExcelImport } from 'react-excel-table/plugins/excel-import';

function ImportButton() {
  const { importFile, isImporting } = useExcelImport({
    columnMapping: {
      'Fecha': 'date',
      'Monto': 'amount',
    },
    // Security enabled by default
  });

  const handleFile = async (e) => {
    const file = e.target.files[0];
    const result = await importFile(file);
    setData(result.rows);
  };

  return <input type="file" onChange={handleFile} disabled={isImporting} />;
}

Security Options

useExcelImport({
  columnMapping,
  security: {
    maxFileSize: 5 * 1024 * 1024, // 5MB
    maxRows: 5000,
    blockFormulaInjection: true, // Block =, +, -, @
    sanitizeText: true,          // Remove XSS patterns
    stripHtml: true,             // Remove HTML tags
  },
});

Export Plugin

Export to Excel or CSV with formula injection protection.

npm install exceljs  # For Excel export
import { useExcelExport, exportToCSV } from 'react-excel-table/plugins/excel-export';

function ExportButtons({ data, columns }) {
  const { exportToExcel, isExporting } = useExcelExport(data, {
    filename: 'report',
    columns,
  });

  return (
    <>
      <button onClick={exportToExcel}>Export Excel</button>
      <button onClick={() => exportToCSV(data, { filename: 'report' })}>
        Export CSV
      </button>
    </>
  );
}

Keyboard Shortcuts

| Key | Action | |-----|--------| | Arrow Keys | Navigate cells | | Tab | Next cell | | Shift+Tab | Previous cell | | Enter | Edit / Confirm | | Escape | Cancel / Exit fullscreen | | F11 | Toggle fullscreen |


TypeScript

import type { ColumnConfig, RowData } from 'react-excel-table';

// Your data must have an id field
interface Transaction extends RowData {
  id: string;
  date: string;
  amount: number;
}

// Columns are fully typed
const columns: ColumnConfig<Transaction>[] = [
  { accessorKey: 'date', header: 'Date', dataType: 'date' },
  { accessorKey: 'amount', header: 'Amount', dataType: 'currency' },
];

API Reference

ExcelTable Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | data | T[] | Required | Data array | | columns | ColumnConfig[] | Required | Column definitions | | loading | boolean | false | Loading state | | onSave | function | - | Save handler | | onDelete | function | - | Delete handler | | onAddRow | function | - | New row factory | | onModifiedCellsChange | function | - | Change callback | | isReadOnlyRow | function | - | Row lock checker | | isLinkedRow | function | - | Linked row indicator | | className | string | - | Container class |


Security

This library includes protection against common attacks:

  • Formula Injection - Values starting with =, +, -, @ are neutralized
  • XSS - HTML tags and dangerous patterns are stripped
  • File Validation - Size limits, extension whitelist
  • Path Traversal - Suspicious filenames are rejected

All security features are enabled by default.


Browser Support

Chrome, Firefox, Safari, Edge (last 2 versions)


Contributing

See CONTRIBUTING.md


License

MIT

react-excel-table