What's the problem?
We already have the useDataGrid query hook working on the ui-kit, however, we don’t have a component that consumes it, also in order to implement the new SQL Playground in Console, we’ll require to have a DataGrid component for the result visualization.
What are the requirements?
Following the same pattern we have for other components, the DataGrid component should provide a higher-level API that enables customers to setup a basic DataGrid easily but also enable exposing a lower-level API to access the inner table components directly, hopefully the library we use enables us to export its API directly similar to what we do on Chart.js with chartConfigProps.
We already have the useDataGrid hook to query the data so the most important concern is how we display it and enable customizing it.
For v1, we can probably focus on getting a basic version out while we provide data visualization features that we also require on Console
- Default state should render a table with basic styles, with a column to index rows (example from Snowflake)

- Columns should be resizable in order to enable viewing larger elements
- Cells should be selectable and open a drawer with the cell’s data, in case of containing a JSON, it should be formatted. This drawer should also be customizable and provide an option to disable it
- Rows should enable/disable showing a cell with the row’s index to the left
- Clicking on a row’s index should select the row and open a drawer with the row’s data. This drawer should also be customizable and provide an option to disable it
- DataGrid should include built-in pagination
- Clicking on a column header should change sorting, clicking once should set to
ASC, clicking twice should set to DESC and clicking a third time should reset, sorting should be made client-side for static mode and server-side for connected mode.
Requirements for table component:
The DataGrid component should return a table with the received data from DataGrid API,
- Should enable column resize
- Rows should listen to click events and send row data
- Cells should listen to click events and send cell data
- Should enable pagination
- Should be based on
<table /> elements for better a11y
- Should be fully customizable
- Should enable sorting by column
- Should enable showing/hiding row numbers
- Should enable showing/hiding headers
- Should enable showing a drawer on column/cell click
- Should support virtualized scrolling
- Good performance with thousands of rows or more.
- Sticky columns
- Download query data as .csv
- Enable keyboard interactions (selecting whole table, copying a row/cell)
In pro of following consistency with the way we implement charts, helper components, etc we should probably opt for finding a library that would best fit our needs
Candidates:
Tanstack Table provides a headless React hook that makes it easy to implement a Table component, this is similar to what we do today with base-ui’s Select component
✅ Should enable column resize
✅ Should enable pagination
✅ Should be based on <table /> elements for better a11y (you can base it either on div elements or table)
✅ Should be fully customizable (as it’s a headless hook we have full control on the table styles’ customization)
✅ Should enable sorting by column
✅ Should enable showing/hiding row numbers
✅ Should enable showing/hiding headers
✅ Should enable showing a drawer on column/cell click
✅ Should be a lightweight library (752kb npm, 15kb with tree-shaking)
✅ Should be a well maintained library (last commit yesterday)
| Pros |
Cons |
| React-Table is a popular library with 23.6k stars on https://github.com/tanstack/table |
Pronounced learning curve as it is not a component itself but a headless hook |
| Maintained by Tanstack which is the same team that maintains React-Query |
|
| As it is a headless hook, that enables us to implement future features even if those are not directly supported by React-Table |
|
| Extensive documentation with many examples |
|
react-data-grid provides a react component for building data grids, react-data-grid is currently in beta
✅ Should enable column resize
❌ Should enable pagination (does not provide built-in support for pagination)
⚠️ Should be based on <table /> elements for better a11y (based on div elements)
⚠️ Should be fully customizable
- react-data-grid exports a high level component that receives a
renderers prop, this one enables overriding their Checkbox component, Row , SortStatus ,noRowsFallback, while this provides a certain level of customization some things seems to be missing (e.g header)
✅ Should enable sorting by column
✅ Should enable showing/hiding row numbers
❌ Should enable showing/hiding headers
✅ Should enable showing a drawer on column/cell click
⚠️ Should be a lightweight library (752kb might be not so lightweight for a headless hook library)
✅ Should be a well maintained library (last commit 4 days ago)
Other options are either paid or not as good as Tanstack Table, we decided to proceed with Tanstack Table
Detailed design
The component should receive a set of headers and rows for static mode, as well as other properties we already set in static mode for other components.
<DataGrid headers={[]} rows={[]} ...othercommonprops />
Subcomponents should also include a className and style prop in order to enable styles customization.
Loader state
For loader we probably want to do something different to just a loading rectangle, we probably want to try something similar to console, cells in loading state and headers shown for static mode, for connected mode cells should be in loading state as well

Requirements implementation
Based on the decision of using Tanstack Table for the Table, we should rely on their examples on how to implement the features we require, here are some of the guides provided by Tanstack table:
Some features however we will have to implement on our own: drawer, exporting to .csv
Interactivity and customization
It’s necessary to enable handling most of interactivity via props, for this we will require:
- Props to handle click events on Cells, Rows and Headers
- Prop to disable/enable the drawer
- Prop to customize drawer content
We can follow our current pattern of using fallbacks/overrides in order to provide the best level of customization, we can have RowOverride, CellOverride, DrawerOverride, HeaderOverride and PaginationOverride
Rows
For rows we would have the rowOverride but also a top-level prop in order to hide the indexes
| Prop |
Type |
Description |
| rowOverride |
Element | ({props: RowProps, RowComponent: Row, CellComponent: Cell}) => Element |
Overrides the row component |
| indexColumn |
'left' | 'right' | 'hide' |
Sets the position of the index column to either left or right or disables it. |
RowProps
| Prop |
Type |
Description |
| onIndexClick |
(rowData: string[] | Element[]) => void |
Callback called when an index (row) is clicked |
| cellValues |
string[] | Element[] |
Values that will fill each Cell |
| className |
string |
Classname to be applied to the Row container |
| styles |
CSSStyles |
CSS Styles to be applied to the Row container |
Cells
| Prop |
Type |
Description |
| cellOverride |
Element | (props: CellProps, CellComponent: Cell) => Element |
Override for the row component |
CellProps
| Prop |
Type |
Description |
| onCellClick |
(cellValue: string | Element) => void |
Callback called when an cell is clicked |
| cellValue |
string | Element |
The value of the cell |
| className |
string |
Classname to be applied to the Cell container |
| styles |
CSSStyles |
CSS Styles to be applied to the Cell container |
onIndexClick and onCellclick should act as middlewares rather than overriding our setup for opening the drawer, however, if the drawer is disabled those should act as overrides
Drawer
For Drawer, besides of having a drawerOverride component we should have a top-level disableDrawer prop so customers can easily just disable it when they require it without having to add a fallback with an empty result.
| Prop |
Type |
Description |
| disableDrawer |
boolean |
When true, will disable the drawer |
| drawerOverride |
Element | (props: DrawerProps, Component: Drawer) => Element |
The override for the drawer component |
DrawerProps
For v1, it would be enough that the Drawer just shows the data in the cell/row but in order to enable customization we’ll need to enable an onClose prop
| Prop |
Type |
Description |
| onClose |
() => void |
Callback called when the close button in the drawer is clicked |
| displayValue |
string | Element |
Value that the Drawer would display |
| className |
string |
Classname to be applied to the Drawer container |
| style |
CSSStyles |
CSS Styles to be applied to the Drawer container |
Pagination
Regarding pagination, we can provide high-level customization as well as low-level customization, for this, we most likely will want to change the rows per page options for now and then customers can fully customize the component with an override prop
| Prop |
Type |
Description |
| pageSizeOptions |
number[] |
The page sizes options for pagination |
| paginationOverride |
Element | (props: PaginationProps, Component: Pagination) => Element |
The override for the pagination component |
| paginationBehavior |
'infinite' | 'paginated' |
Determines whether the pagination should be performed as a virtualized infinite or a paginated way |
The Pagination component should then be uncontrolled, so customers can easily call the setter and default value from props in their custom pagination component as well as the onNext and onBack
PaginationProps
| Prop |
Type |
Description |
| setPageSize |
(pageSize: number) => void |
Setter to be called when the pageSize changes |
| defaultPageSize |
number |
The default pageSize for the paginator, should be one of pageSizeOptions otherwise should throw a warning |
| onNext |
() => void |
Callback to be called when the “next” button is clicked |
| onBack |
() => void |
Callback to be called when the “back” button is clicked |
| currentPage |
number |
The current page index |
| setCurrentPage |
(page: number) => void |
Setter to change the current page |
| hasNext |
boolean |
Whether a next page is available or not |
| hasPrevious |
boolean |
Whether a previous page is available or not |
| className |
string |
Classname to be applied to the Pagination container |
| style |
CSSStyles |
CSS Styles to be applied to the Pagination container |
Then we would have Header which we could split in HeaderRow and HeaderCell those would be very similar to Row and Cell but should be distinct as it’s a common use case to customize the header different to the other rows/cells, additionally we should have a top-level prop to hide the header
| Prop |
Type |
Description |
| hideHeader |
boolean |
If true, hides the header |
Drawbacks
- In order to provide a good level of customization it could require a lot of work, as DataGrid has a lot of components where we should enable customization.
Alternatives
- Customers already have a
useDataGrid hook that they could use in their own tables
Adoption strategy
DataGrid would be a new component, however, customers could be already using the useDataGrid hook, we could encourage them to start using the DataGrid component, however this is not a breaking change nor it has to be mandatory to migrate from useDataGrid to DataGrid component.
Unresolved questions
What component library to use, probably the best option is Tanstack Table, there are not so many good libraries for our use case
- Is this too much for a v1? It is important to provide our customers with enough customization for their use cases which adds a fair amount of work and based on the library we select we may require more or less work on implementing the required features, should we shrink requirements for v1?
- Pagination in static mode. In the current design we only consider connected mode for this, although customers could implement pagination on their own using the override, should we also care about supporting pagination in static mode for v1?
- Should we enable downloading query data as .csv?
What's the problem?
We already have the useDataGrid query hook working on the ui-kit, however, we don’t have a component that consumes it, also in order to implement the new SQL Playground in Console, we’ll require to have a DataGrid component for the result visualization.
What are the requirements?
Following the same pattern we have for other components, the
DataGridcomponent should provide a higher-level API that enables customers to setup a basicDataGrideasily but also enable exposing a lower-level API to access the inner table components directly, hopefully the library we use enables us to export its API directly similar to what we do on Chart.js withchartConfigProps.We already have the
useDataGridhook to query the data so the most important concern is how we display it and enable customizing it.For v1, we can probably focus on getting a basic version out while we provide data visualization features that we also require on Console
ASC, clicking twice should set toDESCand clicking a third time should reset, sorting should be made client-side for static mode and server-side for connected mode.Requirements for table component:
The DataGrid component should return a table with the received data from DataGrid API,
<table />elements for better a11yIn pro of following consistency with the way we implement charts, helper components, etc we should probably opt for finding a library that would best fit our needs
Candidates:
Tanstack Table (React Table)
Tanstack Table provides a headless React hook that makes it easy to implement a Table component, this is similar to what we do today with base-ui’s Select component
✅ Should enable column resize
✅ Should enable pagination
✅ Should be based on
<table />elements for better a11y (you can base it either on div elements or table)✅ Should be fully customizable (as it’s a headless hook we have full control on the table styles’ customization)
✅ Should enable sorting by column
✅ Should enable showing/hiding row numbers
✅ Should enable showing/hiding headers
✅ Should enable showing a drawer on column/cell click
✅ Should be a lightweight library (752kb npm, 15kb with tree-shaking)
✅ Should be a well maintained library (last commit yesterday)
react-data-grid
react-data-grid provides a react component for building data grids,
react-data-gridis currently in beta✅ Should enable column resize
❌ Should enable pagination (does not provide built-in support for pagination)
<table />elements for better a11y (based on div elements)renderersprop, this one enables overriding theirCheckboxcomponent,Row,SortStatus,noRowsFallback, while this provides a certain level of customization some things seems to be missing (e.g header)✅ Should enable sorting by column
✅ Should enable showing/hiding row numbers
❌ Should enable showing/hiding headers
✅ Should enable showing a drawer on column/cell click
✅ Should be a well maintained library (last commit 4 days ago)
Other options are either paid or not as good as Tanstack Table, we decided to proceed with Tanstack Table
Detailed design
The component should receive a set of
headersandrowsfor static mode, as well as other properties we already set in static mode for other components.Subcomponents should also include a
classNameandstyleprop in order to enable styles customization.Loader state
For loader we probably want to do something different to just a loading rectangle, we probably want to try something similar to console, cells in loading state and headers shown for static mode, for connected mode cells should be in loading state as well
Requirements implementation
Based on the decision of using Tanstack Table for the Table, we should rely on their examples on how to implement the features we require, here are some of the guides provided by Tanstack table:
Some features however we will have to implement on our own: drawer, exporting to .csv
Interactivity and customization
It’s necessary to enable handling most of interactivity via props, for this we will require:
We can follow our current pattern of using fallbacks/overrides in order to provide the best level of customization, we can have
RowOverride,CellOverride,DrawerOverride,HeaderOverrideandPaginationOverrideRows
For rows we would have the
rowOverridebut also a top-level prop in order to hide the indexesRowPropsCells
CellProps(cellValue: string | Element) => voidstring | ElementonIndexClickandonCellclickshould act as middlewares rather than overriding our setup for opening the drawer, however, if the drawer is disabled those should act as overridesDrawer
For Drawer, besides of having a
drawerOverridecomponent we should have a top-leveldisableDrawerprop so customers can easily just disable it when they require it without having to add a fallback with an empty result.DrawerPropsFor v1, it would be enough that the Drawer just shows the data in the cell/row but in order to enable customization we’ll need to enable an
onClosepropstring | ElementPagination
Regarding pagination, we can provide high-level customization as well as low-level customization, for this, we most likely will want to change the rows per page options for now and then customers can fully customize the component with an override prop
The
Paginationcomponent should then be uncontrolled, so customers can easily call the setter and default value from props in their custom pagination component as well as theonNextandonBackPaginationPropsThen we would have
Headerwhich we could split inHeaderRowandHeaderCellthose would be very similar toRowandCellbut should be distinct as it’s a common use case to customize the header different to the other rows/cells, additionally we should have a top-level prop to hide the headerDrawbacks
Alternatives
useDataGridhook that they could use in their own tablesAdoption strategy
DataGridwould be a new component, however, customers could be already using theuseDataGridhook, we could encourage them to start using theDataGridcomponent, however this is not a breaking change nor it has to be mandatory to migrate fromuseDataGridtoDataGridcomponent.Unresolved questions
What component library to use, probably the best option is Tanstack Table, there are not so many good libraries for our use case