@vello/react-table
v1.0.4
Published
A high-performance, highly interactive, and easily customizable data table library for React
Downloads
393
Readme
Vello React Table - Official Documentation
⚠️ DEPRECATION & MIGRATION NOTICE ⚠️
The@Vellogrid/reactpackage has been officially deprecated and rebranded to Vello. Please migrate your projects to use@vello/react-tableand@vello/coreto receive the latest updates, premium features, and security patches.
Welcome to the official Vello documentation! Vello is a high-performance, modern, highly interactive, and easily customizable data table library built exclusively for the React.js and Next.js ecosystem (supports both App Router & Pages Router).
🚀 Installation Guide
1. Standard Installation via NPM Registry
Install the core and react packages into your React project using your preferred package manager:
# Using npm
npm install @vello/core @vello/react
# Using pnpm
pnpm add @vello/core @vello/react
# Using yarn
yarn add @vello/core @vello/react💡 Quick Start
Here is a basic example of implementing VelloGrid in your React application. If you are using Next.js (App Router), make sure to add the "use client"; directive at the top of your file.
"use client";
import React, { useState } from 'react';
import { VelloGrid, ColumnConfig } from '@vello/react-table';
// 1. Define your data type
interface Product {
id: number;
name: string;
category: string;
price: number;
}
// 2. Prepare initial data
const initialProducts: Product[] = [
{ id: 1, name: 'MacBook Pro M3', category: 'Laptop', price: 2500 },
{ id: 2, name: 'iPhone 15 Pro', category: 'Smartphone', price: 1200 },
{ id: 3, name: 'iPad Air', category: 'Tablet', price: 600 },
];
export default function App() {
const [products, setProducts] = useState<Product[]>(initialProducts);
// 3. Configure columns
const columns: ColumnConfig<Product>[] = [
{
id: 'id',
header: 'ID',
width: 80,
pinned: 'left',
sortable: true
},
{
id: 'name',
header: 'Product Name',
sortable: true,
filterable: true,
copyable: true
},
{
id: 'category',
header: 'Category',
sortable: true,
filterable: true
},
{
id: 'price',
header: 'Price',
align: 'right',
sortable: true,
render: (row) => `$${row.price.toLocaleString()}`
}
];
return (
<div style={{ padding: '24px', maxWidth: '1200px', margin: '0 auto' }}>
<VelloGrid
tableName="MAIN PRODUCT TABLE"
data={products}
columns={columns}
/>
</div>
);
}🌟 Comprehensive Feature Guide & Code Examples
VelloGrid is packed with enterprise-grade premium features ready to be integrated. Below is an in-depth guide for each feature along with code examples.
1. Virtualization & Performance
VelloGrid uses advanced DOM Windowing techniques where only the rows visible on the screen are physically rendered into the DOM.
- Requirement: The
enableVirtualizationproperty is set totrueand themaxHeightproperty must be defined (e.g.,"500px").
<VelloGrid
tableName="MASSIVE DATA MANAGEMENT"
data={massiveProductsList}
columns={columns}
enableVirtualization={true}
maxHeight="500px" // Maximum height of the scroll area
/>2. Data Editing Module (Inline & Cell Editing)
VelloGrid provides two highly flexible alternatives for direct inline editing within cells:
A. Excel-Style Cell Editing (editMode="cell")
- How it works: The user double-clicks on a cell that has the
editable: trueconfiguration. The cell instantly turns into an active input box. - Keyboard Shortcuts:
Enter: Saves changes and closes the editor.Escape: Cancels changes.Tab: Saves current cell changes and smartly jumps to the next editable cell to the right.Blur(Auto-Save): Automatically saves changes when the cursor leaves or focus shifts.
B. Row-level Inline Editing (editMode="row")
- How it works: Provides a dedicated edit control column that is stickily pinned to the left side.
- Actions:
- Pencil ✏️ Button: Turns all editable cells in the row into input mode simultaneously. The actively edited row receives a premium purple highlight
.vello-row-editing-active. - Save ✔️ Button: Performs batch validation. If successful, triggers a batch update callback. Input boxes that fail validation glow red (invalid border glow) and display a red warning tooltip balloon above them.
- Cancel ❌ Button: Cancels all row edits in a single click.
- Pencil ✏️ Button: Turns all editable cells in the row into input mode simultaneously. The actively edited row receives a premium purple highlight
<VelloGrid
tableName="PRODUCT SALES"
data={products}
columns={[
{ id: 'id', header: 'ID', width: 60 },
{ id: 'name', header: 'Item Name', editable: true, dataType: 'string' },
{
id: 'category',
header: 'Category',
editable: true,
dataType: 'string',
editOptions: {
type: 'select',
options: ['Laptop', 'Smartphone', 'Tablet', 'Accessories']
}
},
{ id: 'price', header: 'Price ($)', editable: true, dataType: 'number' }
]}
editMode="row" // Options: 'cell' | 'row'
// Callback triggered when the Save ✔️ button is clicked (Row-level)
onRowEditSubmit={(rowId, newRowData, originalRow) => {
setProducts(prev => prev.map(p =>
String(p.id) === String(rowId) ? { ...p, ...newRowData } : p
));
}}
// Callback triggered when a Cell is done editing (Excel-style)
onCellEditSubmit={(rowId, columnId, newValue, originalRow) => {
setProducts(prev => prev.map(p =>
String(p.id) === String(rowId) ? { ...p, [columnId]: newValue } : p
));
}}
// Real-time input validation
onCellEditValidate={(columnId, value, row) => {
if (columnId === 'price') {
if (value === null || value === undefined || value === '') {
return 'Price cannot be empty';
}
if (value < 0) {
return 'Price cannot be less than 0';
}
}
if (columnId === 'name' && (!value || String(value).trim() === '')) {
return 'Product name cannot be empty';
}
return true; // Return true if valid, string error if invalid
}}
/>3. Premium Action Column (Column Actions)
VelloGrid provides an interactive action column dynamically pinned to the left or right side for operations such as View Details, Edit, Delete, and Custom Actions.
- Beautiful Design: Buttons are elegantly designed with a lifting hover effect (shadow lift & micro-scale) and harmoniously change colors following hover or selection on the table row.
<VelloGrid
data={products}
columns={columns}
actionConfig={{
headerLabel: "Actions", // Action column title
width: 120, // Column width (px)
pinned: "left", // Pinning position: "left" | "right" | "none"
onView: (row) => alert(`Details: ${row.name}`),
onEdit: (row) => alert(`Edit: ${row.name}`),
onDelete: (row) => {
if (confirm(`Delete "${row.name}"?`)) {
// Delete logic
}
},
customActions: [
{
key: 'star',
label: 'Favorite',
icon: <span style={{ fontSize: '14px' }}>⭐</span>,
onClick: (row) => alert(`${row.name} added to favorites!`),
style: { color: '#fbbf24' } // Custom styling support
}
]
}}
/>4. Row Selection & Rules (Row Selection)
Displays a checkbox in each row for multi-selection of data.
selectMode: Can be configured to return an array of full row objects ('row'), an array of unique strings/IDs ('id'), or any other specific field.isSelectable: You can disable checkboxes on specific rows based on data conditions.
<VelloGrid
data={products}
columns={columns}
enableRowSelection={true}
selectMode="row" // Options: 'row' | 'id' | keyof T
onSelectionChange={(selectedRows) => {
console.log("Selected rows:", selectedRows);
}}
rowConfig={{
// Only rows with a price above $500 can be selected
isSelectable: (row) => row.price > 500
}}
/>5. Row Details Expansion (Row Details Expansion)
Allows users to expand a row (accordion-style) to display detailed information without leaving the table page.
<VelloGrid
data={products}
columns={columns}
showExpandedRows={true}
renderRowDetails={(row) => (
<div style={{ padding: '16px', backgroundColor: '#f8fafc', borderLeft: '4px solid #6366f1' }}>
<h4 style={{ margin: '0 0 8px 0', color: '#1e293b' }}>Technical Specifications: {row.name}</h4>
<p style={{ margin: '0 0 4px 0', fontSize: '14px', color: '#475569' }}>
Category: <strong>{row.category}</strong>
</p>
<p style={{ margin: '0', fontSize: '13px', color: '#64748b' }}>
Official Manufacturer Warranty: 1 Year | Guaranteed Spare Parts.
</p>
</div>
)}
/>6. Smart Column Filtering
Displays a dedicated input filter row below the column headers that dynamically adapts based on the column data type:
string: Searches for substring text matches (contains).number: Provides mathematical comparison operator inputs (equals, greater than, less than).boolean: Custom boolean dropdown (e.g., Active / Inactive) with label customization options.date: Date range picker calendar.
const columns: ColumnConfig<Product>[] = [
{
id: 'name',
header: 'Name',
dataType: 'string',
filterable: true
},
{
id: 'price',
header: 'Price',
dataType: 'number',
filterable: true
},
{
id: 'inStock',
header: 'Status',
dataType: 'boolean',
filterable: true,
booleanLabels: { true: 'Available', false: 'Out of Stock' }
},
{
id: 'releaseDate',
header: 'Release Date',
dataType: 'date',
filterable: true
}
];
// In VelloGrid
<VelloGrid
data={products}
columns={columns}
showFilters={true} // Display the filter input row immediately by default
showGlobalFilter={true} // Toggle filter button in the TopBar
/>7. Custom Header, Footer, & Data Aggregation Summary
You can fully customize the rendering of column headers and footers to present summary aggregation data (e.g., Total Count, Average, or Status).
const columns: ColumnConfig<Product>[] = [
{
id: 'category',
header: 'Category',
renderHeader: (col) => (
<span style={{ display: 'inline-flex', alignItems: 'center', gap: '6px' }}>
📁 {col.header}
</span>
)
},
{
id: 'price',
header: 'Price',
align: 'right',
render: (row) => `$${row.price.toLocaleString()}`,
renderFooter: (col, filteredData) => {
const total = filteredData.reduce((sum, item) => sum + item.price, 0);
return `Total: $${total.toLocaleString()}`;
}
}
];8. Server-Side Fetch API Integration (Manual Mode)
VelloGrid fully supports integration with external API calls (Server-Side Pagination, Sorting, & Filtering). By using the Controlled Component pattern, VelloGrid acts merely as a state emitter, while the client application (parent component) is responsible for fetching data.
Crucial Requirement:
You must turn on all three manual properties (enableManualPagination, enableManualSorting, enableManualFiltering) so the Grid stops processing data on the client side.
<VelloGrid
data={products}
columns={columns}
// 1. Turn off internal processing (Required for Server-Side)
enableManualPagination={true}
enableManualSorting={true}
enableManualFiltering={true}
// 2. Control Loading and Total Data Count from API
isLoading={loading}
totalItems={totalRowsFromApi}
// 3. Catch every table state change to send to API
onStateChange={(newState: VTableState) => {
// A. Pagination
const page = newState.pagination.pageIndex + 1;
const limit = newState.pagination.pageSize;
// B. Global Search
const search = newState.globalFilter;
// C. Sorting (Example output: "price:desc")
const sort = newState.sorting
.map(s => `${s.id}:${s.desc ? 'desc' : 'asc'}`)
.join(',');
// D. Active Column Filters
const filters = newState.columnFilters
.filter(f => f.value !== "" && f.value !== undefined)
.map(f => ({ field: f.id, value: f.value, operator: f.operator }));
// E. Execute API call
fetchMyApi({ page, limit, search, sort, filters });
}}
/>9. Top Bar Custom Button Customization (topBarActions)
You can insert your own custom UI elements (such as Add New, Import action buttons, etc.) directly into the table Header (Top Bar) using the topBarActions property. These elements will appear neatly in the top right corner of the table.
<VelloGrid
topBarActions={
<div style={{ display: 'flex', gap: '8px' }}>
<button onClick={() => alert("Importing...")}>Import CSV</button>
<button onClick={() => alert("Adding...")}>+ Add Data</button>
</div>
}
/>10. State Persistence (Saving Table State)
VelloGrid can automatically save and restore table state (such as pagination, search, hidden columns, and sorting) using various storage mechanisms.
Available Modes
localStorage&sessionStorage: Works out of the box synchronously.url: Automatically synchronizes the critical table state (pagination, sorting, filtering) with the browser's URL query parameters without reloading the page. This is incredibly useful for creating shareable links where another user opening the link will see the exact same table configuration.custom: Ideal for storing state in an external Database or API. Use theonSavecallback to catch state changes and push them to your server. When fetching the state back asynchronously, you should use the Controlled Mode (stateprop) rather thaninitialStateto handle the asynchronous delay properly.
<VelloGrid
// 1. Local Storage (Default - Active)
persistenceConfig={{
enabled: true,
mode: 'localStorage', // or 'sessionStorage'
key: 'vello-my-table-state' // Unique storage key (required)
}}
// 2. URL Query Parameters (Auto-syncs with Address Bar)
// persistenceConfig={{
// enabled: true,
// mode: 'url',
// key: 'vg-state'
// }}
// 3. Custom Storage (e.g., saving to database/API)
// persistenceConfig={{
// enabled: true,
// mode: 'custom',
// onSave(state) {
// console.log("Saving state custom:", state);
// // perform fetch/API call here
// }
// }}
/>11. Row Grouping (Drag & Drop Column Grouping)
The grouping feature allows users to drag column headers to the Top Bar to group rows based on the values in that column.
<VelloGrid
grouping={{
enabled: true
}}
/>12. Error State Banner (Network/API Error Handling)
VelloGrid comes with an integrated Top-Alert Banner to elegantly display API network errors or data fetching failures without destroying the existing table layout or data. The banner features a smooth slide-down accordion animation.
<VelloGrid
data={products}
columns={columns}
errorConfig={{
isError: true, // Trigger to show/hide the banner
message: "500 Internal Server Error. Failed to fetch latest data.",
type: 'error', // Options: 'error' | 'warning' | 'info' (Affects background color)
actionNode: (
<button onClick={() => retryFetch()}>Retry</button>
),
// style: { backgroundColor: '#333', color: '#fff' } // Support for custom CSS
}}
/>🎨 Theming & Icon Customization
VelloGrid uses local CSS Variables to easily customize color palettes instantly without bloating your application bundle size.
A. Configuring the theme Property Object
You can pass a theme configuration object directly to the theme property:
<VelloGrid
data={products}
columns={columns}
theme={{
primary: '#8b5cf6', // Main accent color (Violet)
primaryRgb: '139, 92, 246', // RGB format for transition opacity
background: '#fafafa', // Table background
text: '#1e293b', // Main text color
border: '#cbd5e1', // Border line color
borderTable: true // Show outer table border lines
}}
/>B. Custom CSS Configuration (Global / Variables)
You can also define custom CSS variables globally in your project's .css file to seamlessly align VelloGrid with your application theme:
:root {
--vello-primary: #6366f1;
--vello-primary-rgb: 99, 102, 241;
--vello-bg: #ffffff;
--vello-text: #18181b;
--vello-border: #e4e4e7;
--vello-hover: #f4f4f5;
--vello-header-bg: #f8f8fa;
--vello-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);
}C. Icon Customization
You can replace all built-in VelloGrid SVG icons with custom icons from your preferred icon library (e.g., Lucide-React, React-Icons, etc.):
import { SearchIcon, TrashIcon, CheckIcon } from 'lucide-react';
<VelloGrid
data={products}
columns={columns}
icons={{
Search: <SearchIcon size={14} />,
Check: <CheckIcon size={14} />,
EmptyState: <div style={{ textAlign: 'center', padding: '20px' }}>No data found 😭</div>
}}
/>📝 Comprehensive API Reference
1. <VelloGrid /> Properties (VelloGridProps)
| Property | Data Type | Default Value | Description |
| :--- | :--- | :--- | :--- |
| tableName | string | "VelloGRID" | Datatable title displayed in the top left corner of the TopBar. |
| data | T[] | Required | Array of raw data objects to display in the table. |
| columns | ColumnConfig<T>[] | Required | Array of column configurations. |
| editMode | 'cell' \| 'row' | 'cell' | Editing mode option: single cell (double click) or simultaneous row (✏️ button). |
| onCellEditSubmit | (rowId, colId, val, row) => void | undefined | Callback triggered when a single cell is finished editing and saved (Excel-Style). |
| onRowEditSubmit | (rowId, data, row) => void | undefined | Callback triggered when a single row is finished editing and saved (Row-level). |
| onCellEditValidate| (colId, val, row) => boolean \| string | undefined | Custom validator function. Return true if valid or string error message. |
| enableRowSelection | boolean | false | Displays row selection checkboxes (multi selection). |
| selectMode | 'row' \| 'id' \| keyof T | 'row' | Return format of selection data (id = array of IDs, row = array of row objects). |
| onSelectionChange | (selectedData: any[]) => void | undefined | Callback triggered when the list of selected rows changes. |
| rowConfig | RowConfig<T> | undefined | Configure condition functions for which rows can be selected (isSelectable). |
| showExpandedRows | boolean | false | Enables row expansion button (Row Detail Expansion). |
| renderRowDetails | (row: T) => ReactNode | undefined | Render function to display detailed information panel below the row. |
| showFilters | boolean | false | Displays per-column filter input row below the headers. |
| showGlobalFilter | boolean | false | Displays filter visibility toggle button in TopBar. |
| showGlobalSearch | boolean | true | Displays global text search box in TopBar. |
| searchPlaceholder | string | "Search..." | Placeholder text for global search input. |
| showDensitySwitcher| boolean | true | Displays row density switcher button (sm, md, lg) in TopBar. |
| showDownloadCsv | boolean | true | Displays filtered data export button to .csv file format. |
| actionConfig | GridActionConfig<T> | undefined | Configures row action operation buttons (Edit, View, Delete, Custom). |
| enableVirtualization| boolean | undefined | Enables high-performance virtual scroll (automatic if data > 1000). |
| maxHeight | string | "450px" | Maximum height of the table scroll area (required if virtualization is active). |
| isLoading | boolean | false | Displays premium data loading indicator (skeleton loading). |
| theme | VelloGridTheme | undefined | Configures custom main table theme colors. |
| icons | VelloGridIcons | undefined | Replaces built-in SVG icons with your custom icons. |
| initialState | Partial<VTableState> | undefined | Sets initial table state such as pagination (pageIndex, pageSize). |
| state | Partial<VTableState> | undefined | Controls the table state entirely from the outside (Fully Controlled Mode). |
| enableColumnResizing| boolean | true | Enables boundary drag feature to resize column widths. |
| defaultColumn | Partial<ColumnConfig>| undefined | Default properties to apply automatically to all columns. |
| virtualRowHeight| number | 48 | Specific height of each row in pixels when virtualization is enabled. |
| virtualScrollMaxHeight | string | "450px" | Specific maximum height for the virtual scroll viewport area. |
| density | 'sm' \| 'md' \| 'lg' | 'sm' | Initial density/spacing size of cells in the table. |
| showVisibleColumn | boolean | false | Displays column visibility toggle menu in the TopBar. |
| className | string | undefined | Custom CSS class to apply to the root wrapper of the grid. |
| enablePagination | boolean | true | Disables both the data slicing and hides the pagination UI footer, rendering all data at once. |
| enableManualPagination | boolean | false | Disables client-side pagination processing (Server-Side Mode). |
| enableManualSorting | boolean | false | Disables client-side sorting processing (Server-Side Mode). |
| enableManualFiltering | boolean | false | Disables client-side filtering processing (Server-Side Mode). |
| totalItems | number | undefined | Total number of data items on the server (Required if enableManualPagination=true). |
| errorConfig | VelloGridErrorConfig | undefined | Configuration to display an integrated top-alert error banner. |
| onStateChange | (state: VTableState) => void | undefined | Callback when pagination, sorting, or filtering changes (Server-Side Mode). |
| topBarActions | ReactNode | undefined | Custom UI elements/buttons to be inserted on the right side of the Header (Top Bar). |
| persistenceConfig | VelloGridPersistenceConfig | undefined | Configuration for automatic table state saving to localStorage or sessionStorage. |
| groupingConfig | { enabled: boolean; defaultGroups?: string[] } | undefined | Enables drag-and-drop row grouping based on columns. |
| localeText | Partial<GridLocaleText> | undefined | Custom translation object to override built-in table texts (i18n). |
| getRowClassName | (row: T) => string | undefined | Custom function to dynamically assign specific CSS classes per row. |
| getRowStyle | (row: T) => React.CSSProperties | undefined | Custom function to dynamically inject inline styles specific per row. |
| collapsible | boolean | false | Enables the collapse/expand toggle arrow button in the Top Bar. |
| defaultCollapsed| boolean | false | Sets the default collapsed state of the table on initial render. |
2. Column Configuration Properties (ColumnConfig)
| Property | Type | Default Value | Description |
| :--- | :--- | :--- | :--- |
| id | string | Required | Unique ID for the column (usually matches a key in the data). |
| header | string | Required | Column title to be displayed in the header. |
| render | (row: T) => ReactNode | undefined | Custom function to render cell content in this column. |
| renderHeader| (col: ColumnConfig) => ReactNode | undefined | Custom function to render column title in the header. |
| renderFooter| (col, data) => ReactNode | undefined | Custom function to render content in the bottom row (footer). Receives array of filtered data. |
| sortable | boolean | true | Allows data sorting feature when column title is clicked. |
| filterable | boolean | false | Displays specific filter input below this column title. |
| dataType | 'string' \| 'number' \| 'boolean' \| 'date' | 'string' | Determines column data type to match validation and filter input shapes. |
| booleanLabels| { true: string, false: string } | undefined | Customizes filter dropdown texts if the column data type is boolean. |
| pinned | 'left' \| 'right' | undefined | Pins the column stickily to the left or right edge. |
| align | 'left' \| 'center' \| 'right' | 'left' | Text alignment of column cell content. |
| width | number \| string | undefined | Default column width (in px or percentage string). |
| minWidth | number | 80 | Minimum column width limit during resizing. |
| resizable | boolean | true | Allows this column boundary width to be resized by the user. |
| editable | boolean | false | Allows cells in this column to be edited. |
| editOptions | GridEditOptions | undefined | Additional editor input configuration, such as { type: 'select', options: [...] } for select types. |
| copyable | boolean | false | Displays a quick copy button (copy-to-clipboard) when the cell is hovered. |
3. Action Configuration Properties (GridActionConfig<T>)
| Property | Type | Default Value | Description |
| :--- | :--- | :--- | :--- |
| headerLabel | string | "Actions" | Action column title in the header row. |
| width | number | 75 | Action column width in pixels (px). |
| pinned | 'left' \| 'right' \| 'none' | 'left' | Determines which side the action column is stickily pinned to. |
| onView | (row: T) => void | undefined | Callback triggered when the eye 👁️ view details icon button is clicked. |
| onEdit | (row: T) => void | undefined | Callback triggered when the pencil ✏️ edit icon button is clicked (only appears if editMode="cell"). |
| onDelete | (row: T) => void | undefined | Callback triggered when the trash 🗑️ delete icon button is clicked. |
| customActions | Array<CustomAction> | undefined | List of additional custom actions complete with their own icons and event handlers. |
🛠️ Tips & Best Practices
1. Next.js App Router Handling (Client Components)
VelloGrid components use interactive React states such as useState and event handlers. Always add the "use client"; line at the very top of your wrapper component file when using Next.js App Router.
2. Asynchronous Validation (API Side Validation)
You can perform asynchronous validation by capturing data in the onRowEditSubmit or onCellEditSubmit callbacks, and then sending it to your backend server. If the server replies with an invalid status, revert the state data to its original value (rollback).
const handleRowEditSubmit = async (rowId, newRowData, originalRow) => {
try {
const response = await fetch(`/api/products/${rowId}`, {
method: 'PUT',
body: JSON.stringify(newRowData),
headers: { 'Content-Type': 'application/json' }
});
if (!response.ok) {
throw new Error('Server validation failed');
}
// Save changes to local state if successful
setProducts(prev => prev.map(p => String(p.id) === String(rowId) ? { ...p, ...newRowData } : p));
} catch (error) {
alert(error.message);
// Maintain originalRow / do not update local state
}
};3. Setting Optimal Column Widths
Use a combination of width and minWidth properties in column configuration. For long text columns like "Name" or "Description", it is recommended to give a minimum width of 150 or 200 so content is not cut off when the screen shrinks.
4. Fully Controlled Mode
For advanced cases like synchronizing table state to URL Query Parameters or creating external navigation buttons outside the table component, use the state prop.
Use the Partial<VTableState> type so you only need to inject the state you want to control (e.g., only pagination), and let VelloGrid handle the rest of the state automatically.
import { useState } from 'react';
import { VelloGrid, VTableState } from '@vello/react-table';
export default function App() {
const [tableState, setTableState] = useState<Partial<VTableState>>({
pagination: { pageIndex: 0, pageSize: 10 }
});
return (
<>
<button onClick={() => setTableState(prev => ({
...prev,
pagination: { ...prev.pagination, pageIndex: 4 }
}))}>
Jump to Pg. 3
</button>
<VelloGrid
data={data}
columns={columns}
state={tableState} // Injecting state from outside
onStateChange={(newState) => {
setTableState(newState); // Required reverse synchronization
fetchDataFromServerApi(newState);
}}
/>
</>
);
}