DataTable
A structure that organizes and displays data in sortable grid.
The Basics
What it is
The DataTable component is designed to structure and present related data points in a grid layout, facilitating quick comparison and analysis. It supports both client-side and server-side data fetching, allowing for efficient handling of large datasets.
How it works
DataTable relies on three core elements:
- Column headers: the descriptive titles that appear at the top of each column.
- In sortable columns, column headers have arrow icons for sorting. The user can click the sorting icons (or focus and press the Enter key or Space bar) to reorder the column data in ascending or descending order.
- Data columns: the table's vertical sections. Each column displays data that corresponds to its column header. These columns are optionally sortable.
- Data rows: the horizontal sections that span the data columns. Each row contains one unique set of data points. Rows are optionally expandable and can respond to filter actions.
- Hovering on a row highlights it with a blue background color, to help the user scan across the table.
- If any rows are expandable, the user can click the row’s expand control to show/hide an additional container below it (following rows are pushed down).
Functionally, DataTable can be set to client-side fetching, where data is loaded in memory based on the rowData prop. Alternatively, server-side fetching can be used to load the data progressively for larger data sets.
When to use
- To organize and display structured information
- To help users find and compare data points
When not to use
- For simple image- or text-based lists that do not need as much structure
-
As a replacement for grid. DataTable should only be used when information must be presented in a tabular format, not just to visually align content.
What to use instead
Use grid to visually align elements without the need for additional DataTable functionality.
Use List if you are trying to display a less structured list of data
How to use
To get started, follow these steps to plan your DataTable. The features mentioned here are described in detail in the subsequent sections of this page.
Step 1: Consider What Each Row of Your DataTable Will Capture
- Data rows are the horizontal sections that span your table’s columns. Each row contains a unique set of interrelated data points, often referred to as an observation.
- Decide what one observation will represent in your content. For example, one row could represent one patient, one day, or one entry.
Step 2: Consider What Information Will Exist in the Columns of Your DataTable
- Column headers are the descriptive titles that appear at the top of each column.
- Decide how to organize your columns from left to right in a meaningful order, such as by importance or alphabetically.
- The first column should contain a unique identifier for each row (e.g., "Name" or "ID" in a table of patients) to facilitate easy scanning of data, even after sorting or filtering.
Step 3: Consider the Format of Data in Your Columns
- Data columns are the vertical sections of the table. Each column displays data corresponding to its header and contains a specific data type (e.g., numeric, text).
- Determine the data type required for each of your column. Content can either be defined by the implementing team or captured by user input
- Possible column types include:
- Currency
- Date Input (data inputted from DateInput component)
- Date String
- Icon (contains a Forge Icon)
- Id (number or string)
- Long Text
- Numeric
- Percent
- Radio Group (data inputted from RadioGroup component)
- Select (data inputted from Select component)
- Tag (contains a Forge Tag)
- Text
- Action (contains buttons related to row actions)
- Checkbox (contains checkboxes for selecting rows related to bulk actions)
- Custom (can contain links or buttons to do things like opening a new tab, modal, or popover)
- By default, text is left-aligned, and numbers are right-aligned for easier comparison.
Step 4: Consider What Additional Functionality Your DataTable May Need
- Consider what technical features your users may need in your DataTable:
- Column Configuration: users can optionally show and hide columns or drag and drop to reorder column orders, thus configuring views to meet their needs.
- Sort: users can sort columns by clicking on header icons, enabling ascending or descending order.
- Filter: users can filter options in their table to only display certain rows. Filtering can be applied in three ways:
- Filter Panel: a visual panel that contains FormField elements like select or input allowing users to apply multiple table-level filters in one grouping.
- Column Filters: Icon buttons displayed next to column headers to open popups that filter table one column at a time.
- Quick Filters: a visual panel that surfaces predefined filter combinations such as quick action buttons.
- Search: adds a search bar to the table control panel that filters data based on input for easy data retrieval.
- Expandable Rows: rows can be expanded to reveal additional details, enhancing data context without cluttering the main view.
- Row Click: users can display a context menu when they right-click a table row.
- Action Buttons: an additional column that holds action buttons for editing, deleting, or performing custom actions on each table row.
- Action buttons are configurable and can be added to all rows, some rows, or dynamically defined rows
- Editing
- Inline Editing: users can edit data directly within the table, with validation options to ensure data integrity. Inline edits can be at a custom cell level or dynamically determined by the application.
- Table Edit: users can edit the entire table by triggering an element that opens the entire table in an editable state.
- Row Edit: an action button (edit icon) that, when enabled, opens all cells in the row for editing, transitioning the icons in the action field to save/cancel buttons.
- Adding Entities: users can add a row to the table through the UI using either a modal or a form panel above the table.
- Validation: implementing teams can provide validation logic that appears in the edit views before the user clicks save. This validation can prevent the user from saving and will follow the same guidance as the Standard Error Banner.
- Alerting When Navigating Away: to prevent users from losing unsaved changes, implementing teams can add a pop-up that will automatically appear if users attempt to navigate away or close the tab while edits are unsaved.
- Bulk Actions: users can perform actions on multiple rows simultaneously.
- These bulk actions can be triggered using individual checkboxes, multi-option menus, single action buttons, pop-up modals, or complex multi-action control rows.
- CSV Download: users can download table data in CSV format for external use.
- Refresh: by default, DataTable data is automatically fetched on page reload, but users can also manually refresh the data if needed.
Step 5: Consider How You Would Like to Style Your DataTable
- Style Options to Consider:
- Layout: DataTable offers two layout settings: medium and compact.
- The medium layout (default) is suitable for most tables, while the compact layout is best for dense datasets with many numbers, such as a table of recent transactions.
- Sticky Styling: optional styling that allows columns, row headers, and/or row footers to be sticky, meaning they remain visible as users scroll.
- Pagination: optional styling that adds visual pagination can be added to manage large datasets, with options for client-side and server-side pagination.
- Alert Styling: optional styling that adds alert-colored bars to individual data table rows or alert icons to individual cells.
- Cell Tooltips: optional styling that adds tooltips on a per-cell basis.
- Deleted/Archived/Void Rows: optional styling that visually handles deleted, archived, and voided rows through recoloring of text and background colors.
- Empty State: configurable messaging that allows you to display a placeholder message when the table has no data (e.g., when filters don’t match any data, the search function returns no results, or the user has completed all available tasks).
- Layout: DataTable offers two layout settings: medium and compact.
Style
Design details
DataTable’s column widths are typically determined by the longest string in each column, which makes columns widths vary. This makes it easier for users to scan the table, because it reduces extra white space in the table's cells and shows data points closer together.
By default, DataTable’s width is the sum of its column widths. DataTable width can be set to a specific size, but it shouldn’t be too wide, because this can add white space between data points that makes it harder to scan the table. For this reason, don’t set small DataTables to span the full width of a page.
Row height is set by the layout option:
- Medium (default): 36px row height
- Compact: 24px row height
Placement and hierarchy
Content
To add a title to the DataTable, use the `title` prop. Use title case for this heading (“Today’s Schedule”, not “Today’s schedule”).
Use title case for column headers (“Date of Service”, not “Date of service”). Column headers are automatically displayed in bold. To avoid text wrapping:
- Keep column header text short. Leave out information that’s obvious from the context or the DataTable title. For example, if the DataTable title is “Patients”, use “Name” as a column header, not “Patient Name”.
- Use DataTable’s built-in option for forcing the column header text onto a single line. With this setting enabled, header text is automatically truncated with an ellipsis when the column width is smaller than the width of the header text.
The details
Now that you know how to get started, here are specific instructions for each feature of DataTable linked to live examples of each behavior.
Kitchen Sink Demos of All Features
Name | Description | Storybook Demo with Code Link | Figma Notes |
---|---|---|---|
Client-Side Demo | A demo that shows all available features in client-side DataTable. | data-table-client-side-demo | 'Example DataTable' component can be found in the Data Table page of the Figma libraries. |
Server-Side Demo | A demo that shows all available features in server-side DataTable. |
| 'Example DataTable' component can be found in the Data Table page of the Figma libraries. |
Column Features
Name | Description | Storybook Demo with Code Link | Figma Notes |
---|---|---|---|
Cell Tooltips | Tooltips can be added to individual cells or to column headers. | cell-tooltips-demo | For column headers, tooltips can be mimicked in Figma and is accessed by turning on 'header' boolean property found in the 'TableCell' component. Then, turning on 'tool tip' boolean property nested within the 'cell content' component. |
Column Types |
Possible column types include:
By default, text is left-aligned, and numbers are right-aligned for easier comparison. |
Column types are handled on a case by case basis in Figma. For numeric/percent/currency columns choose 'quantity' type cell content. For text/string choose 'default' cell content type. |
Row Features
Name | Description | Storybook Demo with Code Link | Figma Notes |
---|---|---|---|
Adding Entities |
DataTable users can add rows to the table through the UI using either a modal or a form panel above the table. When a user adds the row, we also refresh the DataTable and data can be passed in in any given order as determined by the consuming team. |
*to add an entity, press the add row button at the very top of the table in the demo | This feature will be added to Figma soon. |
Expandable Rows |
Expandable rows add additional details to rows in the table but do not display them by default. Rather, they are shown when an interactive clickable arrow is toggled on and off for each row.
When row detail information is passed in, the parent row will automatically include a clickable arrow for revealing the detail row. | expandable-row-demo | Row expand icons are shown as 'expandable' a boolean property found in the 'TableCell' component. |
Row Click | Row Click is an optional feature that allows the table viewer to open a configurable context menu when they right-click a table row. This menu is comprised of the forge Menu component. | row-click-demo | Add 'menu' component in Figma to mimic this feature |
Sort, Search, Filter
Name | Description | Storybook Demo with Code Link | Figma Notes |
---|---|---|---|
Filter |
Filtering allows DataTable viewers to only display certain rows based on column criteria. Filtering can be applied in three visual ways:
We have made adding filters easier by providing native support for all current input types that could be filters and ensuring the formatting works as intended. Native filter types include:
Additionally, filters can be created for any custom column or FormField element type to allow filtering based on their unique content. For app-controlled filters that may be located elsewhere on the page or not visible at all, a custom filter can also be written.
Custom filters can also be flexible. or dependent/strict.
|
custom-height-column-example-demo
|
Filtering is found in the following Figma components: Filter Panel: 'DataTable Filter Panel' Quick Filters: 'DataTable Quick Filters' Column Filters: 'Table Cell' as the 'Filter' boolean option available for 'header' type |
Search |
Separate from the filter panel, DataTable also offers a simple text search. The search input field appears immediately above the table in the control row and provides a string-based text search. Consumers can turn off search on specific columns (ex. if you want to have only one searchable column). Search will bring up results with partial matches. The search functionality can be client-side (which works immediately upon typing) or server-side (which requires the user to enter the string first and click the search button). | Search is housed in the 'TableControlRow' component as a boolean layer that can be turned on and off. | |
Sort |
DataTable allows users to sort columns by clicking on arrow icons found next to column headers. This lets users change the order of values in that column (e.g., sorting payment amounts from smallest to largest) and reorders all rows in the DataTable.
| sort-demo | Column sort icons are shown as 'sort' a boolean property found in the 'TableCell' component. |
Edit and Bulk Action Features
Name | Description | Storybook Demo with Code Link | Figma Notes |
---|---|---|---|
Action Buttons |
Action buttons are an additional DataTable column that holds buttons for editing, deleting, or performing custom actions on each table row. Action buttons are located in the right-most cell of each row. This provides a standard, grouped location for any row-level actions you want to provide. Action buttons are configurable and can be added to all rows, some rows, or dynamically defined rows.
| Action buttons can be found in 'right actions' a variant property found in the 'TableCell' component. | |
Bulk Actions |
Bulk actions are actions performed by DataTable users on multiple rows simultaneously. These bulk actions can be triggered using individual checkboxes, multi-option menus, single action buttons, pop-up modals, or complex multi-action control rows.
We have built in the ability to act on multiple rows at the same time. Please be mindful of the language you are putting into your bulk action sections to be clear about the exact action that the user is taking. For example, instead of “Bulk Edit” or “Bulk Assign”, you can put “Update Status” or “Assign Claims”.
|
bulk-edit-demo-button style layout |
Bulk action design is housed in the 'TableControlRow' component as a boolean layer that can be turned on and off. Bulk action styling is handled by nested component 'Table Element Bulk Action'. |
Edit |
We currently offer two types of inline edit built into the table table edit and row edit, both of which provide built-in edit fields for selects and inputs (including date input)*. For custom cells, if you want it to be editable in the table itself you will need to provide an editable state for the cell.
Edit functionality has optional validation and alerting that can be configured as follows:
We also enable the application to determine which columns and rows are editable with the ability to disable editing at a per cell level. For bulk edit (i.e., making the same change to multiple rows at one time) please see Bulk Action feature notes. *Note: You can only have one type of edit available on the table at once. We are planning on adding single cell inline edit functionality, too, which will enable editing/saving one cell at a time. That is currently in development. | Edit functionality is housed within action buttons, which are shown as 'right actions' a variant property found in the 'TableCell' component. |
Table Control Features
Name | Description | Storybook Demo with Code Link | Figma Notes |
---|---|---|---|
Column Configuration | Column configuration is an option in the Table Control row that allows DataTable viewers to show, hide or reorder individual columns, thus configuring views to meet their needs. Reordering is completed using drag and drop functionality, while show/hide is completed with one toggleSwitch per table column. | column-config-demo | Column configuration is housed in the 'TableControlRow' component as a boolean layer that can be turned on and off. |
CSV Download |
CSV download enables downloading a copy of the data available in the table into a CSV.
| csv-download-demo | This feature will be added to Figma soon. |
Deleted/Archived/Void Rows |
Deleted rows can optionally be visually displayed with modified styling. We have standardized the look and interaction on deleted, archived, and voided rows.
The option to show deleted rows can be toggled on and off using a checkbox in the Table Control row. | delete-and-restore-row-demo |
The checkbox to toggle showing deleted rows on and off is housed in the 'TableControlRow' component as a boolean layer called 'show deleted' Deleted styling is found by adjusting the 'state' variant to 'deleted' in the 'cell content' component that is nested within each 'table cell' component. |
Pagination |
Pagination is the grouping of table contents into multiple pages that can be navigated via a visual element called a paginator. In DataTable, the Paginator component is built in to allow navigation. We recommend turning on pagination if you have more than 20 rows in your table. Pagination and row counting can be displayed in the table control row at the top or bottom of your DataTable These supporting elements for pagination are included:
Functionally, you will choose one of these pagination approaches:
|
pagination-default-layout-demo pagination-compact-layout-demo pagination-with-page-jump-demo
| Paginator and Row Count are housed in the 'TableControlRow' component as 'Table Element Row Count' and 'Paginator' respectively. |
Refresh |
DataTable data is automatically fetched on page reload, but if you have a need to allow your users to refresh data more frequently, we offer the ability to manually refresh the data. When manual refresh is enabled the refresh icon will appear above the table along with the last time the data was pulled. When the button is clicked the table will call the consuming application to fetch the data again. The last fetch time of data can also be displayed next to the refresh button allowing the user to easily see when it was last updated. You can also trigger loading with an external component. | This feature will be added to Figma soon. |
UI Change Features
Name | Description | Storybook Demo with Code Link | Figma Notes |
---|---|---|---|
Alert Styling |
DataTable alert styling exists in two forms:
|
Colored alert bars are added via 'left actions' a variant property found in the 'TableCell' component. Individual alert icons are added via 'alert' a boolean found in the 'cell content' component that is nested within the 'TableCell' component. | |
Layout | DataTable offers two layout settings: medium and compact. The medium layout (default) is suitable for most tables, while the compact layout is best for dense datasets with many numbers, such as a table of recent transactions. |
(use the button at the top of the control panel called 'Demo Options' to toggle layout) | Table Layout is handled by the 'Table Layout' variant found in the 'TableCell' component. Layout must be applied to ALL cells/rows in your figma example. |
Sticky Styling | Sticky styling is an optional UI change that allows columns, row headers, and/or row footers to be sticky, meaning they remain visible as users scroll to assist with visual table navigation. |
Sticky headers, footers, and columns cannot be perfectly mimicked in Figma. To quasi-mimick the feature, select all cells in one row or one column and use prototyping features to set the elements as sticky and the other columns/rows as 'scroll with parent'. For help with this please reach out to Veronica Agne. | |
Entity name Changes |
You can define what each row of a table means and displaying table row counts with that name. i.e. 50 people instead of 50 rows |
This feature will be added to Figma soon. | |
Column Header Styling | For unique UI needs, column headers can be styled with line breaks or to wrap/not wrap accordingly. |
To access line breaks or second lines in column headers, first turn on the boolean 'header' prop in the 'Table Cell' component then toggle on '2nd line' boolean prop in the nested 'cell content' component | |
Custom UI Styling | For unique UI needs, the entire table can have class and style modifications for a custom look. |
This is not available in Figma. |
Demos
Coding
Developer tips
Storybook files
DataTable has so many features that it's difficult to create representative demos for everything in this guide, as performance of this page would degrade. For this reason, it's strongly encouraged to view the storybook files in the source code and see them run at http://go/forge-storybook.
createDataTable factory function
DataTable breaks many paradigms shared by a typical Forge component, in part because it is so huge. There is no DataTable
export. Instead, most aspects of DataTable are accessed via the createDataTable
factory function.
const DT = createDataTable<RowData>({ tableId: 'patient-table' });const patients:RowData[] = [...]const PatientTable = (): ReactElement => {return <DT.DataTable tableType="client-side" columns={columns} rowData={patients} {...props} />}
The reason behind the createDataTable
factory function is to bind the type of RowData
to the implementation. It's important to call createDataTable outside of a component's render function. Otherwise, React will unmount and remount the entire table on every re-render of your component.
While Forge does export all of the Typescript types cited in the props documentation, we also provide abstractions of these types for easier access. For example, to define your own CustomAddRowComponent
, you need the DataTableHooks
to define its supported props. You can either
import { DataTableHooks } from '@athena/forge';const CustomAddRowComponent = (props: DataTableHooks<RowData>): ReactElement => <></>;
or
const DT = createDataTable<RowData>({ tableId: 'patient-table' });const CustomAddRowComponent = (props: typeof DT.Type.Hooks): ReactElement => <></>;
See createDataTable implementation for details of what is included.
DataTable vs. SingletonDataTable vs. Advanced DataTable
- DT.DataTable works like a regular React component. Whenever the props of your DataTable change, the entire DataTable component will be re-rendered. You can use
ref.current.getState
to get the current internal state andref.current.dispatch
to change it. - DT.SingletonDataTable can only be used if your React app needs just one DataTable instance. DT.SingletonDataTable performs better than DT.DataTable because it only re-renders the subcomponents when specific states change. You can also use
ref.current.getState
to get the current internal state andref.current.dispatch
to change it.- You can't create a reusable React component using based on the SingletonDataTable.
- SingletonDataTable is implemented using the React Context API.
- Advanced DataTable: DT.Provider, DT.DataTableRender, DT.DataTableInterface, DT.useSelector, and DT.useDispatch are used for the scalable DataTable component.
- Scalability: Advanced DataTable > DT.SingletonDataTable > DT.DataTable. It’s recommended to start with the DT.DataTable.
Repository
Implementation links
DataTable directory in Bitbucket
Implementation details
It is strongly recommended to familiarize yourself with the Forge source code. While this documentation is a best effort to document the intent and usage of a component, sometimes some features only become clear when looking at the source code. Also, looking at Forge's source code may help identify and fix bugs in either your application or Forge itself.
Storybook files
Forge maintains at least one storybook file per component. While the primary audience for these files is typically the Forge team, these storybook files may cover usages of the component not covered by a demo. The storybook for the latest version of forge can be found at go/forge-storybook.
Testing library
Forge strongly encourages using testing-library to write tests for your application.
"The more your tests resemble the way your software is used, the more confidence they can give you."
If you're having trouble testing a Forge component using testing-library, it would be a good idea to see how Forge tests its own components. For the most part, Forge tries to use screen.getByRole as much as it can, as that API provides the best feedback on a11y compliance. Forge discourages the use of document.querySelector and screen.getByTestId as both APIs encourage using implementation details to test your component, and discourage adding roles to your component.
With that being said, many of Forge's components were not built with accessibility in mind. These components do break the recommendations listed above.
Import statements
In Nimbus applications
athenaOne serves the Forge bundle independently from your application's bundle. Importing Forge components directly from '@athena/forge' takes advantage of this feature.
import { createDataTable } from '@athena/forge'
In standalone applications
Importing components using the exact path to the module takes advantage of webpack's tree shaking feature. Webpack will include only that module and its dependencies.
import { createDataTable } from '@athena/forge/DataTable';
To use this import guidance, Typescript applications must use typescript >= 4.7.3, and should add this setting to their tsconfig.json file:
{ "compilerOptions": { "moduleResolution": "Node16", } } If this setting doesn't work for your application, use this import statement instead:
import { createDataTable } from '@athena/forge/dist/DataTable';