notion-spark-datatable
v1.0.29
Published
A flexible and customizable data table component built with React and TanStack Table, featuring Notion-style UI components
Maintainers
Readme
Notion Spark Datatable
A modern, modular data table component built with React and TanStack Table, featuring Notion-style UI components and a clean hooks-based architecture.
✨ Features
- 🏗️ Modular Architecture: Clean separation of concerns with custom hooks for each feature
- 🎨 Notion-style Components: Built-in status indicators, tags, and buttons with proper Notion colors
- 🔍 Advanced Filtering: Multi-column filtering with 7 filter operators and localStorage persistence
- 📊 Smart Grouping: Automatic group expansion with localStorage persistence
- 📏 Responsive Column Sizing: Compact, overflow-preventing column widths
- 🔄 Drag & Drop: Column reordering with protected action column
- 📱 Responsive Design: Works on all screen sizes without horizontal scrolling
- ⚡ High Performance: Built with TanStack Table for optimal performance
- 🎯 TypeScript Support: Full type safety and IntelliSense
- 💾 State Persistence: All table state saved to localStorage automatically
🚀 Quick Start
1. Install the package
npm install notion-spark-datatable2. Use the component
import { TableComponent } from 'notion-spark-datatable';
function App() {
return (
<TableComponent
tableId="my-table"
data={yourData}
columns={yourColumns}
config={{
enableSearch: true,
enableFilters: true,
enableSorting: true,
enableGrouping: true,
enableResizing: true,
enableDragging: true,
}}
onCreate={handleCreate}
onEdit={handleEdit}
onDelete={handleDelete}
/>
);
}🏗️ Architecture
The component uses a modular hooks architecture for clean separation of concerns:
Core Hooks
useColumnOrder- Manages column ordering and drag & dropuseGrouping- Handles grouping state and auto-expansionuseColumnFormatting- Manages number/percent/currency formattinguseFilters- Advanced filtering with 7 operatorsuseColumnSizing- Responsive column sizing and resizinguseColumnVisibility- Column visibility management
UI Components
HeaderContextMenu- Context menu for column headersColumnFormattingMenu- Number formatting optionsFilterPanel- Advanced filtering interfaceToolbar- Table controls and actions
📋 Column Types
The component supports various column types with automatic rendering. Each type is designed for specific data patterns:
const columns = [
{
id: 'title',
type: 'title', // Editable title column (always visible)
header: 'Task Name',
accessorKey: 'name'
},
{
id: 'status',
type: 'status', // Status indicator with dots
header: 'Status',
accessorKey: 'status'
},
{
id: 'tags',
type: 'tag', // Colored tag component
header: 'Tags',
accessorKey: 'tags'
},
{
id: 'dueDate',
type: 'date', // Date formatting with dayjs
header: 'Due Date',
accessorKey: 'dueDate'
},
{
id: 'number',
type: 'number', // Number formatting (number/percent/currency)
header: 'Number',
accessorKey: 'number'
},
{
id: 'boolean',
type: 'boolean', // Boolean toggle
header: 'Boolean',
accessorKey: 'boolean'
},
{
id: 'url',
type: 'url', // Clickable URL links
header: 'Website',
accessorKey: 'website'
},
{
id: 'relation',
type: 'relation', // Relation picker with search
header: 'Category',
accessorKey: 'category'
}
];Column Type Guidelines
title: Use for the main identifier of each row (e.g., task name, project title, user name)status: Use for state indicators (e.g., active, pending, completed, critical)tag: Use for categorization (e.g., tags, labels, categories, types)date: Use for temporal data (e.g., due dates, creation dates, deadlines)number: Use for numeric values (e.g., numbers, percentages, amounts, quantities)boolean: Use for true/false flags (e.g., boolean values, flags, toggles)url: Use for clickable links (e.g., websites, documentation, resources)relation: Use for related data with search (e.g., categories, users, projects)text: Use for editable text fieldscustom: Use for custom cell renderers
🔧 Props
Table Configuration
The config prop allows you to control which features are enabled:
const config = {
enableSearch: true, // Global search functionality
enableFilters: true, // Advanced filtering panel
enableSorting: true, // Column sorting
enableGrouping: true, // Row grouping
enableResizing: true, // Column resizing
enableDragging: true, // Column reordering
enableEditing: false, // Inline cell editing
};All options default to true except enableEditing which defaults to false.
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| tableId | string | ❌ | Unique ID for localStorage persistence (auto-generated if not provided) |
| data | T[] | ✅ | Array of data objects |
| columns | ColumnDefinition<T>[] | ✅ | Column definitions |
| config | TableConfig | ❌ | Global table configuration options |
| onCreate | (row: T) => void | ❌ | Handler for creating new items |
| onEdit | (row: T) => void | ❌ | Handler for editing items |
| onDelete | (id: string) => void | ❌ | Handler for deleting items |
| onRelationPick | (field: string, q: string) => Promise<Array<{ id: string; name: string }>> | ❌ | Handler for relation search |
| renderActions | (row: T) => React.ReactNode | ❌ | Custom action column renderer |
| renderCreateButton | () => React.ReactNode | ❌ | Custom create button renderer |
🎯 Example
import React from 'react';
import { TableComponent } from 'notion-spark-datatable';
const columns = [
{
id: 'title',
type: 'title',
header: 'Task Name',
accessorKey: 'name'
},
{
id: 'status',
type: 'status',
header: 'Status',
accessorKey: 'status'
},
{
id: 'tags',
type: 'tag',
header: 'Tags',
accessorKey: 'tags'
},
{
id: 'dueDate',
type: 'date',
header: 'Due Date',
accessorKey: 'dueDate'
},
{
id: 'number',
type: 'number',
header: 'Number',
accessorKey: 'number'
},
{
id: 'boolean',
type: 'boolean',
header: 'Boolean',
accessorKey: 'boolean'
}
];
const data = [
{ id: '1', name: 'Complete project', status: 'active', tags: 'development', dueDate: '2024-01-15', number: 85, boolean: true },
{ id: '2', name: 'Review code', status: 'pending', tags: 'review', dueDate: '2024-01-20', number: 92, boolean: true },
{ id: '3', name: 'Bug fix', status: 'critical', tags: 'maintenance', dueDate: '2024-01-10', number: 78, boolean: false }
];
function MyTable() {
return (
<TableComponent
tableId="my-tasks-table"
data={data}
columns={columns}
config={{
enableSearch: true,
enableFilters: true,
enableSorting: true,
enableGrouping: true,
enableResizing: true,
enableDragging: true,
}}
onCreate={() => console.log('Create new')}
onEdit={(row) => console.log('Edit', row)}
onDelete={(id) => console.log('Delete', id)}
/>
);
}
export default MyTable;🎨 Features in Detail
🔍 Advanced Filtering
- 7 Filter Operators: equals, not equals, contains, starts with, ends with, greater than, less than
- Multi-column Support: Apply multiple filters simultaneously
- Persistent State: Filters saved to localStorage automatically
- Smart UI: Filter panel with easy-to-use controls
📊 Smart Grouping
- Auto-expansion: Groups automatically expand when grouping is applied
- Persistent State: Grouping and expansion state saved to localStorage
- Flexible Grouping: Group by any column type
- Group Sorting: Sort groups by value or count
📏 Responsive Column Sizing
- Compact Design: Optimized widths to prevent horizontal scrolling
- Content-aware: Different widths for different column types
- Resizable: Users can resize columns as needed
- Protected Columns: Action column always visible and properly sized
🔄 Drag & Drop
- Column Reordering: Drag columns to reorder them
- Protected Actions: Action column cannot be moved or hidden
- Smooth Animations: Built with @dnd-kit for smooth interactions
- Keyboard Support: Full accessibility support
💾 State Persistence
- Automatic Saving: All table state saved to localStorage
- Table-specific: Each table instance has its own storage
- Persistent Features: Column order, visibility, sizing, filters, grouping, formatting
🎨 Styling
No CSS imports needed! All components include inline styles and work out of the box:
- ✅ Notion Color System: Uses proper Notion colors (gray, blue, green, yellow, red, purple, pink)
- ✅ Flexible Status System: Auto-detects colors from status text or override with
colorprop - ✅ Tag Components: All color variants with proper radius and padding
- ✅ Button Styling: Primary, secondary, ghost, destructive variants
- ✅ Table Styling: Headers, rows, gradients, and hover effects
- ✅ Responsive Design: No horizontal scrolling, fits all screen sizes
🔧 Development
Build the package
npm run buildBuild library version
npm run build:libDevelopment server
npm run dev📦 Package Contents
TableComponent- Main table component with all featuresNotionStatus- Status indicator componentNotionTag- Tag component with color variantsNotionButton- Button component with variants- Custom Hooks - All core functionality hooks
- UI Components - Header context menu, filter panel, toolbar
- TypeScript Types - Full type definitions
🚀 What's New in v1.0.12
- ✨ Modular Hooks Architecture - Clean separation of concerns
- 🔍 Advanced Filtering System - 7 filter operators with persistence
- 📊 Smart Grouping - Auto-expansion with localStorage
- 📏 Responsive Column Sizing - No more horizontal scrolling
- 🔄 Protected Action Column - Always visible, always on the right
- 💾 State Persistence - All settings saved automatically
- 🧹 Clean Code - Removed debug logs, optimized performance
- 🏷️ Generic Column Names - Clear, non-redundant field naming
- 🌙 Enhanced Column Types - Added URL, relation, and custom cell types
- ⚙️ Improved Configuration - Better config prop documentation and examples
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📄 License
This project is licensed under the MIT License.
