DEV Community

Cover image for Building a Google Sheets–Like Table Component with TanStack Table, Zod, and ShadCN/UI
Jackson Kasi
Jackson Kasi Subscriber

Posted on

Building a Google Sheets–Like Table Component with TanStack Table, Zod, and ShadCN/UI

Hi everyone! 👋 I wanted to share a story about my quest to find an open-source table component with Google Sheets–style functionality. My requirements were quite advanced:

  • Grouping rows
  • Showing totals
  • Validating cells in real-time (e.g., for financial data)
  • Dynamically enabling/disabling rows and columns
  • Supporting an intuitive, spreadsheet-like editing experience

After an extensive search, I couldn’t find an existing library or code snippet that perfectly fit my use case. I needed something powerful enough to handle complex financial work in a CMS, yet still easy to customize. So, I decided to build my own component leveraging these tools:

I’m calling this component FlexiSheet. Here’s an overview of what it offers and how it can help you create spreadsheet-like tables in your React application.


Why FlexiSheet?

  1. Editable Cells with Validation

    Each cell can be edited directly in the table. If you need validation (e.g., ensuring the value is a non-negative number), you can define a Zod schema. If the new value doesn’t pass validation, FlexiSheet can highlight the cell and prevent submission until it’s valid.

  2. Row and Column Disabling

    Certain rows/columns can be disabled for editing. This is perfect for locking down areas meant for static values, or for read-only columns that compute total/aggregated data.

  3. Grouping Rows

    By assigning a simple headerKey to each row, the component automatically groups rows by category. This is handy if you have multiple items belonging to the same group, like “Budget Items” or “Expense Items.”

  4. Footer Rows and Custom Footers

    You can display a totals row at the bottom of the table and even attach a fully customizable footer element. For example, a row summing up monthly expenses or a quick note on invoice terms.

  5. Column Resizing

    Enable column resizing out of the box by toggling a single prop and defining size, minSize, and maxSize in the column definitions.


Example Usage

Here’s a short example demonstrating how to define your data and columns, including validation with Zod:

import { z } from "zod";

// Define Zod schemas
const materialNameSchema = z.string().min(1, "Material name is required");
const quantitySchema = z.number().nonnegative().optional();
const costSchema = z.number().min(0, "Cost must be >= 0");

// Define your columns
const columns = [
  {
    accessorKey: "materialName",
    header: "Material Name",
    validationSchema: materialNameSchema,
  },
  {
    accessorKey: "quantity",
    header: "Quantity",
    validationSchema: quantitySchema,
  },
  {
    accessorKey: "cost",
    header: "Cost",
    validationSchema: costSchema,
  },
];

// Your data
const initialData = [
  { headerKey: "Expenses", materialName: "Wood", quantity: 5, cost: 100 },
  { headerKey: "Expenses", materialName: "Paint", quantity: 3, cost: 50 },
];

// Render the table
function App() {
  const [data, setData] = useState(initialData);

  const handleEdit = (rowIndex, columnId, value) => {
    // Update state if validation passes
    const newData = [...data];
    newData[rowIndex] = { ...newData[rowIndex], [columnId]: value };
    setData(newData);
  };

  return (
    <SheetTable
      columns={columns}
      data={data}
      onEdit={handleEdit}
      // Example: disable "materialName" column for editing
      disabledColumns={["materialName"]}
      // Example: group rows by headerKey
      showHeader
    />
  );
}
Enter fullscreen mode Exit fullscreen mode

And that’s it! You’ll have a table that behaves like a spreadsheet—rows can be grouped by category (headerKey), columns can be validated (validationSchema), and totals can be displayed in the footer. It’s a flexible foundation for building powerful, spreadsheet-like features in any React app.


Want to Learn More?

I’ve created a detailed README.md with full installation instructions and additional examples. I’m also open to feature requests—if there’s something you’d like to see added (conditional formatting, advanced filtering, etc.), please let me know!

If you find this project helpful, feel free to star it ⭐on GitHub. I appreciate the support, and it helps me continue adding new features.

Thanks for reading to the end, and happy coding! 😊

Top comments (2)

Collapse
 
thesohailjafri profile image
Sohail SJ | TheZenLabs

Lord tanstack, the quality of package he have written is just unreal

Collapse
 
jacksonkasi profile image
Jackson Kasi • Edited

😅Yes, ❤️ tanstack