@saadbaig/sprintx-ui
v1.0.1
Published
A high-performance React table component with virtual scrolling, resizable columns, and inline editing
Maintainers
Readme
@saadbaig/sprintx-ui
A high-performance React table component library with virtual scrolling, resizable columns, and inline editing. Built with React 19, TypeScript, and Tailwind CSS v4.
Features
✨ Virtual Scrolling - Smooth performance with 10,000+ rows using TanStack Virtual 🎨 ClickUp-style Design - Clean, modern aesthetics with OKLCH colors 📏 Resizable Columns - Drag handles with min/max constraints ✏️ Inline Editing - Click-to-edit with keyboard navigation 📌 Fixed Header - Sticky header stays visible during scroll 📍 Fixed First Column - Pin the first column for easy reference 📝 Truncate with Tooltip - Automatic ellipsis with hover tooltips ♿ Accessible - Full ARIA support and keyboard navigation 📦 Lightweight - < 50KB gzipped (excluding React) 🎯 TypeScript - Full type safety with comprehensive types
Installation
npm install @saadbaig/sprintx-uiPeer Dependencies
Make sure you have the required peer dependencies installed:
npm install react react-domQuick Start
import { Table } from '@saadbaig/sprintx-ui';
import '@saadbaig/sprintx-ui/styles';
interface User {
id: number;
name: string;
email: string;
role: string;
}
const columns = [
{
id: 'name',
header: 'Name',
accessorKey: 'name',
width: 200,
editable: true,
fixed: true // Fixed first column
},
{
id: 'email',
header: 'Email',
accessorKey: 'email',
width: 250
},
{
id: 'role',
header: 'Role',
accessorKey: 'role',
width: 150
}
];
const data: User[] = [
{ id: 1, name: 'Alice Johnson', email: '[email protected]', role: 'Engineer' },
{ id: 2, name: 'Bob Smith', email: '[email protected]', role: 'Designer' }
];
function App() {
return (
<Table
data={data}
columns={columns}
height={600}
fixedHeader
fixedFirstColumn
/>
);
}API Reference
Table Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| data | TData[] | Required | Array of data objects |
| columns | ColumnDef<TData>[] | Required | Column definitions |
| height | number \| string | 600 | Container height |
| width | number \| string | '100%' | Container width |
| virtualScroll | boolean | Auto | Enable virtual scrolling (auto for 100+ rows) |
| rowHeight | number | 32 | Height of each row in pixels |
| overscan | number | 5 | Extra rows to render outside viewport |
| fixedHeader | boolean | true | Make header sticky |
| fixedFirstColumn | boolean | false | Make first column sticky |
| loading | boolean | false | Show loading state |
| emptyMessage | string | 'No data' | Message when data is empty |
| onCellEdit | function | - | Callback when cell is edited |
| onColumnResize | function | - | Callback when column is resized |
| onRowClick | function | - | Callback when row is clicked |
| ariaLabel | string | - | Accessible label for the table |
ColumnDef
interface ColumnDef<TData> {
id: string; // Unique column identifier
header: string | React.ReactNode; // Header content
// Data access
accessorKey?: keyof TData; // Property key to access
accessorFn?: (row: TData) => unknown; // Custom accessor function
// Rendering
cell?: (props: CellContext<TData>) => React.ReactNode;
// Sizing
width?: number; // Default: 150px
minWidth?: number; // Default: 50px
maxWidth?: number; // Default: 800px
// Features
resizable?: boolean; // Default: true
editable?: boolean; // Default: false
fixed?: boolean; // Fixed column (first only)
// Styling
align?: 'left' | 'center' | 'right'; // Default: 'left'
className?: string; // Custom CSS class
}Examples
Custom Cell Renderer
const columns = [
{
id: 'status',
header: 'Status',
accessorKey: 'status',
cell: ({ value }) => (
<span className={value === 'active' ? 'badge-success' : 'badge-inactive'}>
{value}
</span>
)
}
];Inline Editing
const [data, setData] = useState(users);
const handleCellEdit = (event) => {
const newData = [...data];
newData[event.rowIndex] = {
...newData[event.rowIndex],
[event.column.accessorKey]: event.newValue
};
setData(newData);
};
<Table
data={data}
columns={columns}
onCellEdit={handleCellEdit}
/>Virtual Scrolling with Large Dataset
// Automatically enabled for 100+ rows
<Table
data={largeDataset} // 10,000+ rows
columns={columns}
height={600}
virtualScroll
/>Styling
The library uses Tailwind CSS v4 with OKLCH color space. You can customize colors by overriding CSS variables:
:root {
--surface-primary: 100% 0 0; /* White */
--surface-secondary: 98% 0 0; /* Light gray */
--surface-hover: 96% 0 0; /* Hover background */
--border-subtle: 90% 0 0; /* Borders */
--text-primary: 25% 0 0; /* Near black */
--text-secondary: 50% 0 0; /* Medium gray */
--primary: 60% 0.15 250; /* Blue accent */
}Dark Mode
.dark {
--surface-primary: 20% 0 0;
--surface-secondary: 25% 0 0;
--surface-hover: 30% 0 0;
--border-subtle: 35% 0 0;
--text-primary: 98% 0 0;
--text-secondary: 70% 0 0;
}Keyboard Navigation
- Arrow Keys - Navigate between cells
- Tab / Shift+Tab - Navigate forward/backward
- Enter - Start editing (if editable)
- Escape - Cancel editing
- Enter (in edit mode) - Commit changes
Browser Support
- Chrome/Edge (last 2 versions)
- Firefox (last 2 versions)
- Safari (last 2 versions)
Performance
- Initial render: < 100ms for 10,000 rows
- Scroll FPS: 60fps consistent
- Bundle size: < 50KB gzipped (excluding React)
- Memory usage: < 50MB for 100,000 rows
Development
# Install dependencies
npm install
# Run tests
npm test
# Run Storybook
npm run storybook
# Build library
npm run build
# Type check
npm run type-checkContributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT © Saad Baig
