Web apps introduction
Learn how Retool web apps work and the fundamental concepts involved.
This guide serves as an introduction to Retool web apps. It covers many of the concepts and terminology you can expect to use as you build apps using the web-based IDE. After reading this page, you should have a good understanding of the fundamentals for building Retool apps.
Add UI components
The user interface of a Retool app is made up of components. These are interface elements, such as a text input field or a table, with which users interact.
Components are objects with internal state. Retool exposes properties, methods, and events with which you can interact. Property values change as you configure or interact with components. For example, the Table component's selectedRow
property contains an array of values for the currently selected row.
You use Retool's drag-and-drop components library in the IDE to assemble and configure an app's UI. You position components anywhere on the canvas, and can adjust their position and size.
Connect components together
Most component properties are editable. You configure them in the IDE with either static values (string
, number
, boolean
, array
, and object
) or reference other component values using {{ }}
embedded expressions, similar to the use of template literals.
You reference property values using dot notation. In the following example, The Default value setting in the IDE references {{table1.selectedRow.name}}
. As a result, {{textInput1.value}}
always corresponds to the name from the selected table row.
Use JavaScript expressions for values
Retool performs string interpolation and evaluates {{ }}
embedded expressions as JavaScript. As a result, you can write JavaScript code—that evaluates and returns a value synchronously—almost anywhere. This enables you to dynamically set property values using transformations or conditional logic to build complex apps.
Explore some common JavaScript expressions using the examples below.
- Truthy statement
- Ternary operator
- Data transformation
The Alert component's Hidden (hidden
) property in the IDE uses a truthy statement that evaluates as true
if the user is a member of the Sales team. Using !
at the start of the expression inverts the returned value from true
to false
. As a result, the alert only appears when a Sales team member is selected.
{{!table1.selectedRow.teams.includes("Sales")}}
The Alert component's Type (type
) and Title (title
) properties in the IDE use conditional logic to determine what value to use. If the date range doesn't include today's date, the alert changes.
// Type
{{moment().isBetween(dateRange1.value.start, dateRange1.value.end) ? 'success' : 'error'}}
// Title
Today is {{ moment.isBetween(dateRange1.value.start, dateRange1.value.end) ? null : 'not' }} within the date range.
The Table component's Data source (data
) property in the IDE uses slice()
to retrieve an index range from the listUsers
query. The start and end values are determined by the Range Slider component. Adjusting the range automatically runs the query and updates the table.
{{
listUsers.data.slice(rangeSlider1.value.start,rangeSlider1.value.end)}}
Connect your data using resources
A resource is a saved set of user-configured properties that determines how Retool connects to a data source, such as a PostgreSQL database or REST API. You create a resource for each data source you want to use with Retool, then write queries to interact with them.
Each resource has configuration options that Retool uses when interacting with a data source. This simplifies how you query data sources while ensuring access is secure.
When a resource query is run, Retool proxies the request to the data source, server-side, using the resource's configuration settings. This means only Retool directly connects to a data source, not your users.
Read and write data using queries
A query is a piece of code you write to interact with a resource and perform CRUD operations. As with components, queries maintain an internal state and expose properties. Queries can also perform asynchronous actions and run simultaneously with other queries.
Queries are not part of an app's user interface. You reference the query's data
property to read and display data in components for which users can interact. Queries can also reference component input values and write them back to the data source.
- Read data
- Write data
The Table component's Data source (data
) property in the IDE is set to query1. Running the query retrieves the specified data in the query statement, which is then displayed in the table.
query2 is set to update or create a record into the sample_users table. It uses a specified id
to determine which record to update. Running the query updates or creates a record using the input values available in {{form1.data}}
.
Connect components and queries together for dynamic interfaces
Under the hood, Retool maintains a dependency graph for each app. This represents all property values and where they're referenced. Whenever a property changes, all downstream references using embedded expressions automatically update. This is similar to how spreadsheet formulas work when referencing cell values; if a referenced value changes then the formula instantly updates its result.
You can chain embedded expressions together by referencing values that also use embedded expressions. Any input value changes automatically propagate through the entire app. This makes it possible to build powerful applications with very few lines of code.
The dependency graph enables Retool to prevent you from creating circular dependencies, where two or more properties rely on each other to function. If you attempt to reference values that rely on one another, the IDE displays a warning.
The following example demonstrates how the dependency graph connects components and queries together within an app. The resource query references {{textInput1.value}}
and runs automatically whenever this value changes. The table references {{query1.data}}
and displays updated results in real-time.
Control and run queries with event handlers
You configure event handlers to perform actions whenever a specific event occurs, such as a button click or query error. There are numerous actions available, such as setting component values and triggering queries.
The following example uses an event handler to display a notification whenever a Saturday or Sunday is selected in the date input field.
Transform data using JavaScript transformers
While you can use JavaScript within {{ }}
embedded expressions, you may need to manipulate data and implement complex logic to produce values, such as filtering or joining data sets.
A JavaScript transformer is a reusable block of JavaScript. You reference property values using embedded expressions and the results of the transformation are output on the transformer's value
property using a return
statement.
The following example uses a JavaScript transformer to split a list of names into first and last names. The Listbox component references {{transformer1.value}}
, which provides an array of last names.
Transformers are maintained by the dependency graph and continually output a transformed value. If you make changes to any values in the dependency chain, the transformer automatically updates.
If you only need to transform query data, you can include transformation code directly in the query. The transformed data is then made available in the query's data
property.
Script apps with JavaScript
You can write JavaScript code to control app behavior, set property values, and more. Components and queries are globally scoped and include built-in methods to control their state. These methods can accept supported parameters, such as string or index values. In either case, you only need to use standard JavaScript notation, not {{ }}
embedded expressions.
JavaScript queries can output data using a return
statement.
The following example adjusts the selected date by a specified number of days, then sets this as the value for the calendar.
Embed content and build custom components
Retool's component library contains over 100 UI components, from input fields to image grids. For complex use cases that require UI components not currently provided, you can embed custom content or build a custom component. These components also have state and you can use {{ }}
embedded expressions.
- HTML: A container for custom HTML and CSS code.
- IFrame: An embedded web page that supports permissions to allow or deny downloads, form submissions, microphone and camera access, and popups.
- Custom Component Libraries: A library of custom-built, embedded component using React and TypeScript. Build once and then deploy into any app.
The following example demonstrates the HTML component.
Wrap up
Using these fundamental concepts, you can build complex web apps that:
- Contain polished user interfaces that can adapt to your needs.
- Dynamically reference values anywhere using dependency chains.
- Connect with almost any API and database to interact with your data.
- Perform actions using conditional logic in response to user events or script apps to control behavior.
The following example combines these concepts to create a user subscription dashboard that can filter, search, and edit users. Selecting a user in the table opens the Drawer frame with input fields prefilled with the selected row data.
Next steps
You now have a basic understanding of how to build a Retool app. Check out the web app tutorial to build a complete app from start to finish.