Skip to main content

Advanced App Examples

These examples explain how to use Retool's components, queries, and logic to create more complex applications. They provide additional context related to common components, resources, and options.


This guide assumes that:


Unnest objects into individual columns

API responses sometimes have nested objects that don’t map well to the Retool Table component. This can cause undesirable nested text when you visualize the data.

There are two solutions that can solve this issue:

  1. Concatenate a nested object
  2. Create individual columns per nested object

In the first solution, we use the Table component’s mapped value attribute to unnest the objects and create a legible address in a single column.

Inspect the Table component, select the column with the nested object, and add the following to Mapped value: {{ self.street.concat(" ",, ", ", "self.state, ", ", self.zipcode) }}

In the second solution, we split the nested object into individual legible columns by using the Table's custom columns.

Inspect the Table component, and add a new custom column for each nested object like the following: currentRow.address.street.

Download the JSON file to try it out yourself.

Auto populate a modal with selected table row metadata

A common Retool use case is to build a view for an Operations team to edit data from a table in a modal view. Auto-populating fields is a common best practice we recommend.

There are two solutions here:

  1. Using a catch-all modal component
  2. Using a table’s Action button and a modal component

In the first solution, we use a modal component. This modal has various text input components that use the table’s selectedRow fields. For each text input component, you can use the selected row’s metadata and set the Default value to {{ }}.

The second solution is similar but it uses the Table’s Action column. Select your table, and scroll down to Actions and add an action. Actions can run a query, open another Retool page, open a web page, or copy to a clipboard. In this use case, it runs a query to open a modal.

Add a modal to your app and set the Hidden value to true; seeing the modal button is not necessary here since we have action buttons on our table. Next, add a JavaScript query to trigger opening the modal component, We can now hook these queries and components together. Go back to your Table’s Actions, set the action button type to Run a query and the Action query to your JavaScript query. Like the first solution, you can use a table’s selected row metadata and auto populate your components.

Download the JSON file to try it out yourself.

Auto populate filters with table values

Filters are commonly created for data tables. In this example, filters are auto populated with values from the table. Additionally, this example explains how to auto populate values that are duplicated in columns.

After loading your data into a table, pull in Select components to facilitate filtering. For each Select component, set the Option to Mapped and wrap your data in JavaScript like this: {{ Array.from(new Set( => }}

After all the filters are created, go to the Query Builder and add a JavaScript transformer to filter data based on the user’s selected filters:

let data = {{ raw_data.value }}

let company = {{ select1.value }};
let job_title = {{ select2.value }};
let location = {{ select3.value }};

return data
.filter(x => company == "" || company == null || === company)
.filter(x => job_title == "" || job_title == null || x.job_title === job_title)
.filter(x => location == "" || location == null || x.location === location)

Go back to your table and set the data to the JavaScript transformer data to complete the filters.

Download the JSON file to try it out yourself.

User configurable table columns

When displaying tabular data with lots of columns, it's more efficient to display a subset of columns. In such situations, you can reduce an application's data density using the Table component's dynamic column settings feature as demonstrated in this app.

  • A variable is used to store a list of objects that correspond to each column's settings in the dataset being displayed in the table. In this example, each column has the following keys defined:

    • name: human-readable name of the column used in the multiselect dropdown.
    • key: data key corresponding to this column in the array to populate the table component.
    • type: type of column to use for displaying this column as per dynamic column types.
  • A multiselect component is used to allow the user to select which columns to display in the table. We use the name key from the variable described above to populate the options for this component. Depending on the desired UI, a different component could be used for this purpose as well (e.g., checkbox group).

Download the JSON file to try it out yourself.

Color code columns and rows in a table

Table components are commonly designed to color code columns and rows depending on a condition. In this example, we'll build out this design pattern using the row background color table properties.

We'll walk through these solutions after loading your data into a table:

  1. Using row color to color code rows
  2. Using the background color property to color code columns

For the first design pattern, in addition to adding a Table component, we'll use a TextInput and NumberInput component to set the conditional. The user will be allowed to specify the color of the row through the TextInput and set the row color code condition based on the NumberInput. Next, inspect your table, and under the Styles section, insert the following JavaScript snippet into the Row color property. Note that we'll also use the {{ currentRow }} table variable to access the row that we are evaluating the conditional on.

{ == numberInput1.value ? textInput1.value : "";

For the second design pattern, inspect the column you want to color code. Under the Styles section, use the Background color property to color code the column. In this example, we'll use the value in each cell of the color column to color code by indexing into the {{ currentRow.color }} value.

Download the JSON file to try it out yourself.

GraphQL cursor based pagination

Cursor based pagination is often used when working with large datasets to increase performance and reduce latency. This examples uses GraphQL cursor based pagination with the Table component to limit how much data queries return.

1. Server side table pagination

The Table component supports server side pagination, which you can enable in the Pagination section. Set the Pagination type to GraphQL Relay cursor based. This surfaces three variables that you can use in our GraphQL query: Previous cursor, Next cursor, Has next page.

2. GraphQL pagination query

When writing the query, you might want use numerous variables to enable GraphQL pagination. Most importantly, you need to pass the first, last, after_cursor, and before_cursor variables in the query. After that, you can leverage the Table pagination variables detailed in the previous section to correctly pass cursor information in the Query Builder.

3. Connecting table component and query

You can now go back to your Table component's Pagination section, and fill in the Previous cursor, Next cursor, and Has next page variables with references to your GraphQL query data.

Download the JSON file to try it out yourself.

For more examples and information on pagination, see the guide to Server Side Pagination.

Return all paginated results

In some scenarios, you might need to access all data from a pagination resource. This example explains how to do this with a REST API and a JavaScript query, which calls the API query as many times as you need.

First, instantiate a cursor by creating an offset URL parameter with the value set to {{ offset }} in the REST API query. Note that offset is undefined -- the JavaScript query will inject the value using additionalScope. See the JavaScript API reference for more information.

Then write a JavaScript query that recursively calls the API query until you receive all the data. If your resource returns an offset value, you can use that returned offset in the JavaScript query and have this query loop as many times as the offset is returned (i.e., until all the data is returned). If your resource does not return an offset value, the query code in this app will instead use the query limit length to determine when all data has been received (i.e., when the query data length is less than the limit, all data has been returned).

Download the JSON file to try it out yourself.

For more examples and information on pagination, read the guide to Server Side Pagination.

Select, MultiSelect, ListView

Searchable dropdowns

Retool's Select, Multiselect, and Listbox components support captions and icons that make long option lists easier to understand.

These components support fuzzy searching as well as captions, which make it possible for users to see a subset of options that correspond to a search term. Try searching for "incident" in the application dropdown to see this in action. Other search methodologies (e.g., case sensitive search) are also supported - see the Search option under the Advanced section of the Inspector.

Download the JSON file to try it out yourself.


The Chart component uses Plotly, and can build a wide variety of different charts (check out Plotly's documentation). In this example, we cover a wide variety of charts: bubble, double y-axis, funnel, gantt, bullet, and 3D charts.

Oftentimes you have to reconstruct your data to match the Plotly data schema in order to render a chart correctly. We recommend using a JavaScript transformer to iterate through your dataset to accomplish this. You can check out the code in the app export.

Additionally, for more complex charts (beyond simple bar, line, scatter, and pie charts), you need to modify the Layout Plotly JSON object which can be found in the Inspection tab.

Download the JSON file) to try it out yourself.

Customize Plotly Hovertext

In this example, we'll walk through adding the ability to customize the hovertext of a graph in Plotly using the chart component.

After loading data into the chart, inspect the component and select the Plotly JSON tab. Define a separate text property within the data field that is set to the array of values you'd like to display as hovertext. Then in the hovertemplate field, reference the text property to set the new values for the hovertext (check out the plotly hovertext docs for more information).

Download the JSON file to try it out yourself.

Leveraging permissions in Retool

Dynamically show or hide components based on environments

You can dynamically alter an app's design depending on the current environment. In this example, we'll walk through how to dynamically show or hide components based on the current environment. We'll use the Hidden property in our components and leverage the {{retoolContext.environment}} property in Retool, whose value displays the name of the environment currently in use.

Drag the components that you want to dynamically hide or show to the Canvas. In this example, an Alert component and a Button component are used to programatically switch the environment. Inspect the Alert component and set the Hidden property to {{ retoolContext.environment == 'production' }} and {{ retoolContext.environment == 'staging' }} accordingly.

Create a JavaScript query, and add the following, which uses the _environment variable to open the Retool app with the corresponding environment credentials. Use an event handler to trigger this query upon clicking the button component.

if (retoolContext.environment !== "staging") {
utils.openUrl(urlparams.href.split("?")[0] + "?_environment=staging", {
newTab: false,
forceReload: true,
} else {
utils.openUrl(urlparams.href.split("?")[0] + "?_environment=production", {
newTab: false,
forceReload: true,

You can then create a Resource with staging and production environments defined. Once you've configured your environment, write a JavaScript query that connects to this resource and store the query data inside a table. When you click on the component, notice that both the alert and table components dynamically change.

Download the JSON file to try it out yourself.

App customization

Using CSS to change an app's font

A common Retool design pattern is to universally change the font of all components. In this example, we'll use CSS to customize a script that changes the font at an app-level. Retool's {{...}} syntax can be used in conjunction with Custom CSS to build dynamically styled applications.

Click the App actions menu at the top right and select Scripts and styles. Under the CSS tab, add the following snippet:

@import url('');

.retool-canvas * {
font-family: 'Roboto', serif !important;
font-size: 14px;

After you save this snippet, go back to the app canvas and you'll see the font changes reflect across all components.

Download the JSON file to try it out yourself.

Customizing URL parameters

As you begin to build more apps on Retool, a common pattern is to send information from one app to another. In this example, we'll walk through how to customize URL query parameters to include specific values in the first app and use them to set the state of the second app.

In the first app, after setting the data inside your table component, add the ability to click into another application by inspecting a column, changing it to the Button column type, and configure the on click property to open another Retool page. Then, configure the URL by adding a memberID parameter that is set to the value of the cell with the {{ self }} keyword.

Now, when you click to go to the second app, the page will have a URL that looks like this:

To set the state of the second app based on the custom URl parameter we just defined, use the {{ urlparams.hash.memberID }} field to selectively filter through the table.

Download the JSON files to try it out yourself: