Skip to main content

Display and edit datasets with the Table component

Learn how to display and interact with data using tables.

Tables are a common way to view and interact with your data. You can sort, filter, paginate, and download rows of information. Tables also support row selection and insertion, server-side pagination, and custom columns.

In June 2023, Retool introduced a new Table component. The previous version is now deprecated. For more information about the two versions, refer to the migration guide.

Demo

Try out the app to see tables in action (edits are disabled).

Load data in a table

When you drag a Table component to the Canvas, it automatically displays data from one of your queries. If you don't have any queries, Retool initially populates the table with demo data. You can change the data displayed in a table by editing the Data source property. From the dropdown, you can select a query, use JavaScript (e.g., queryName.data), or input an array.

Change column types

When you add tables to the Canvas, Retool tries to infer the column types. You can also set column types manually by clicking the column in the right panel, and selecting the type from the Format dropdown.

Set a primary key

Retool recommends setting a primary key column to uniquely identify each row of data. If your data already has an ID column, Retool automatically uses it for the primary key. You can also manually set it to any column that is guaranteed to be unique.

If you don't want to show the primary key column in your table, select the column and set its Hidden property to true.

Set source keys

You can set an optional source key on each column to pull data from your data source. For example, you could set the source ID to populate the table column with data from the data source's ID column.

Regenerate columns

You can regenerate columns after your data source changes by selecting Regenerate Columns in the Inspector. This functionality parses a random sample of entries in your data and adds any missing columns to your table, removes the primary key, and resets the width of your columns. It does not remove custom columns or override other modifications to existing columns. If your entries have varied properties, the random sample of entries might not detect every column in your data. To avoid this issue, you can manually add your columns or transform your data into a consistent shape before passing it to the table.

Editable table columns

After populating a table with data, you can make columns editable and change cell values. To make a column editable, click ••• next to the column, then select Make editable. You can also select a column and click the Editable checkbox.

Click a cell to edit its value. When you edit cells, changes are saved in the table's changesetArray property. This tracks the changes but it doesn't update the underlying data source that your query connects to. To save edits back to your data source, you must write a query to update your data. For example, saving changes to a PostgreSQL database can be done using a bulk update query.

After creating the bulk update query, you need to connect it to the table. Select the table and scroll to the Add-ons section. Add a Save actions add-on. Select the add-on, and then add an event handler that runs the bulk update query.

Add new data to tables

You can add rows to tables and save the changes as new data. To do this, drag in a Form component and click Generate form. This opens a modal where you can select the table you previously dragged onto the Canvas.

Have the form trigger an update query to add a record.

Dynamic values in new rows

You can use dynamic values if you have columns you don't want users to edit, or if you want to automate some of the values added in a row. These values are generated when the row is added, and don't require manual input from the user. For example, if your table has a timestamp column, you can use {{ moment() }} to generate the timestamp when the query runs.

Any {{ }} values can be used while creating rows in a table

Automatically reload table data

If you want to automatically reload table data when changes are saved, add an event handler to the query that updates your data source. Configure the event handler so that when the query succeeds, it runs the query that populates your table.

Set background colors

Set background colors for the entire table using the Styles settings in the Inspector. Setting the Background color changes the background for the entire table, but there are also options for alternating row colors, setting the heading color, etc.

Column background colors

To set background colors on individual columns, select the column and edit the background color.

Row background colors

You can use JavaScript to set row colors dynamically. For example, setting the Row color to {{ currentRow.quantity > 100 ? "green" : "red" }} makes every row with a quantity of greater than 100 green, and every row with a quantity less than 100 red.

Toolbars

Tables include a toolbar by default with filter, download, and refresh functionality. Click the Toolbar in the Add-ons section to add and remove toolbar buttons. You can add custom buttons and change the toolbar location as well.

Custom columns

You can add custom columns to tables using the + button above the list of columns. Custom columns are often used to calculate data based on other values in your Retool app. For example, if you have a monthlyIncome column and you want to calculate a yearlyIncome column, you could use {{ currentSourceRow.monthlyIncome * 12 }} as the value.

Custom columns have the same properties as regular table columns.

Configure actions

Retool automatically includes some actions by default, such as Filter, Download, and Refresh.

You can add actions that are displayed as buttons when hovering over a row in a Table. You can attach event handlers to actions to trigger queries, control components, or call other APIs.

Now when the button is clicked in the table, the modal opens.

Sort, filter, and customize data presentation

Tables come with prebuilt functionality for sorting and filtering data. You can click column headers to sort columns, and you can add toolbars to tables that include filter options.

You can also configure a standalone Filter component to filter table data. After adding the component, connect the filter to the table by enabling the filter's Link to table option and selecting the table.

To use JavaScript to manage filters, see the filterStack section.

Show and hide columns

When you click a column, there's a Hidden property that you can set to true or conditionally control with JavaScript.

Row selection

Single row selection is enabled by default, but tables also support multiple row selection, or you can disable it completely. Selecting multiple rows is often useful when your app needs to make bulk actions. Navigate to the Interaction > Row selection section to change these settings.

Pagination

You can choose between Pagination and Scroll options for handling overflow items.

You can also enable server-side pagination. You write queries that include parameters to define a subset of data to retrieve, server-side. Retool recommends this when working with large datasets to reduce the amount of data your table uses, which can help your app's performance.

Sorting of tables using server-side pagination must be done on the server. You can write queries that use the table's sortArray property to achieve this.

To enable search for a table, drag a Text Input component to the Canvas. Next, click on the Table component and navigate to the Interaction section. Set the Search term property to {{ textInput1.value }} (the name of the Text Input component might be different in your app) to connect the Text Input component to the table. This enables search across all the table's columns, and Retool provides options for fuzzy, exact, and case insensitive searches.

Row selection persistence

Some applications need to track the table's selected rows even while the user is filtering, sorting, or paginating through data. You can enable this in the Interaction section by selecting the Persist row selection checkbox.

Column sort modes

Sort modes provide additional options for sorting individual columns. Using a sort mode can be useful when columns contain multiple values, or when sorting by ascending or descending values doesn't meet your requirements. There are four sort modes.

  • Default: sorts based on the mapped value. If the mapped value is unset, the raw value is used.
  • Raw: sorts based on the raw value, regardless of the mapped value.
  • Options: sorts based on a list of options you create manually.
  • Disabled: disables column sort modes.

Common table variables

currentSourceRow, item, and i are commonly used with tables. item and i work with other components, but they have unique meanings when used with table column settings. With tables, i is the index of the current row in the original dataset, and item is the value of the current cell.

Variables like currentSourceRow and item are useful in situations where you want to access values in a table. For example, {{ item * 10 }} takes the current cell and multiplies it by ten. You can also do something like {{self + ' ' + '(Last sale: + currentSourceRow.last_sale)'}} to combine two values and map them to a column.

i is often used to iterate over a set of values and perform some kind of action. For example, you can iterate over each row in a table and update values, make API requests, send emails, etc. For example, this JavaScript transformer iterates over all rows in table1, and returns each sales person with over 200 sales.

JavaScript transformer
var salesPerson = {{ table1.data }};
var highSales = salesPerson.filter(i => i.sales > 200);
return highSales;

See the Table component reference documentation for more information on properties, events, and JavaScript methods that you can use with tables.

filterStack

filterStack is an object that contains all the filters applied to the table. It includes a filters array with and and or operators for comparing filters. You can write JavaScript to configure the filterStack with these methods:

  • setFilterStack
  • clearFilterStack
  • setFilter
  • clearFilter
setFilterStack
table1.setFilterStack({
filters: [
{ columnId: "id", operator: "=", value: 1 },
{ columnId: "id", operator: "=", value: 2 },
],
operator: "and",
});

See the list below for all available operators. Some operators accept both text and symbol options.

  • lessThan, <
  • lessThanOrEquals, <=
  • greaterThan, >
  • greaterThanOrEquals, >=
  • equals, =
  • doesNotEqual, !=
  • is
  • isNot
  • includes
  • doesNotInclude
  • isTrue
  • isFalse
  • isEmpty
  • isNotEmpty
  • intersects
  • isOneOf
  • isNoneOf
  • isBefore
  • isAfter

See the Table component documentation for more information about table properties and methods.

selectRow

You can use selectRow to select specific rows in a table. There are two modes you can use to specify the row: key and index. Use key to pass the primary key to select the row. Otherwise, use index and pass an indexType to select a row.

index accepts a single index or a list of indexes.

selectRow examples
// Selects the row with primary key 4

table1.selectRow({ mode: "key", key: 4 });

// Selects the row that represents table1.data[4]

table1.selectRow({ mode: "index", indexType: "data", index: 4 });

// Selects the fifth row visible on the table

table1.selectRow({ mode: "index", indexType: "display", index: 4 });

// Selects the rows that represent table1.data[3] and table1.data[4]

table1.selectRow({ mode: "index", indexType: "data", index: [3, 4] });

Configure advanced settings

You can use advanced customization options to control how tables display data. Select a table and open the Advanced settings in the right panel.

Expandable rows

You can configure rows with an expandable area in which you can add components. For example, the table below contains book inventory information. You can enable Expandable rows and then add an Image component to the area that can display the image of the book when selected.

Group rows

You can group rows by their column values. This organizes the table in either ascending or descending order based on the column values. For example, the table below groups rows based on whether the books are on sale.

Editable columns cannot be grouped.

Column aggregation

When you group rows, you can optionally add column aggregation to individual columns. This requires that:

  • The column format is either numerical or boolean.
  • The column you want to aggregate is not the same column set in the Group by rows setting.

For example, this table is grouped by the On sale column, which enables aggregation for columns like Quantity.

Similarly, you can add a Summary row add-on to your table and configure aggregation options for each column. The column formats still need to be either numerical or boolean.

Dynamic column settings

Dynamic column settings allow you to reconfigure table columns, including their labels and how values in the columns are formatted. You do this primarily by mapping different values for the column's label and format, but you can also hide columns and apply different properties. Using dynamic column settings is particularly useful when the data source's schema changes.

For example, this app allows users to display stock values for a selected date range.

The raw data for the table doesn't match exactly how it's displayed though. Notice that each object contains the ticker and a set of dates with the stock prices.

To display the data correctly, dynamic column settings are used to configure the column labels and formats. In this example, item represents the column key, which is either the ticker value or a date.