Group and generate input fields with the Form component
Learn how to assemble an input form using the Form component.
The Form component functions as a container for input components, providing you with complete control over a form's layout and design. You create a form by adding input components or generating them automatically using the schema of a Table or a connected PostgreSQL, MySQL, or MS SQL database.
This guide walks you through building an app and form using the Form component. You can fill in the form to create a record or update existing data by selecting a record from a table and populating the form. The form also increments IDs automatically.
Demo
Try out the app to see the form in action (submissions are disabled).
Generate the inputs
You can manually add form inputs or generate them from a resource or table. To generate inputs, add a form to the canvas and click Generate form. This opens a modal where you can select a resource or table, along with the inputs.
Retool evaluates each column to set an appropriate label and input type, but you can edit these properties as well. You can also deselect columns that you don't want to use in your form.
When you generate a form from a database, Retool automatically adds a query that's configured to create a record. You can connect this query to your form using an event handler to write data back to your database. Forms generated from tables don't include this query, so you need to create a query or configure a similar action to use with form submission.
Open an app and drag a Form component onto the canvas. New forms are initially empty but you can generate inputs from tables, databases, or add them manually.
You can uncheck individual columns to exclude them from the form. This is useful if you don't want users to provide certain information, such as IDs or timestamps. You can also change the generated input type or label, and whether the field should be required.
Each input is generated with a value for Form data key—shown in the Interaction section of the Inspector—that corresponds to the column name from the table.
Validate submissions
Forms can check the validation status of inputs—enable Validate inputs on submit in the Interaction section of the Inspector. Each input component supports several validation options. Validation for a selected input is configured in the Validation section of the Inspector.
Validation supports options such as pattern matching (URL, email, or regular expression) and minimum and maximum lengths. Select the Image URL input and change the pattern to URL so invalid URL formats produce a validation error.
For JSON Schema Form components, you define validation rules in the JSON schema. You can also enable automatic validation by enabling Live validation in the Inspector.
You can also modify input properties of JSON Schema Form components by updating the type field. This can be useful if fields need to accept null values or you need to modify your form to more closely match your data.
Submit the form to create a record
When you generate a Form using a resource, Retool also creates a query (form1SubmitToProducts
in the screenshot), to insert new records into the database when the form is submitted. You must add this query manually when you use forms generated from tables or you generate forms manually.
Fill in the form and click Submit to create a new record in your database. Click the ↻ button on the table to refresh it and see the newly created record.
For JSON Schema Form components, you must create this query manually and attach it to the form as an event handler.
Populate the form to update existing records
You can also use this form to make changes to an existing record. A common approach is to populate a form with data from a selected table row and then submit changes to update the record.
You can set the form's Data source property and automatically populate its inputs using the selected table row data. The Form component matches each input's data key to a corresponding column name from the table to determine where values should go.
For example, this ternary operator sets the form's initial data only if a table row is selected:
{
{
table1.selectedRow ? table1.selectedRow : null;
}
}
If set, a form's Data source overrides any default values for nested components.
Update the query to create and update records
Remember to save changes to your queries by clicking Save.
The form's existing query only creates new records. However, you can update the existing query to create or update records when the form is submitted.
Change the action type
Select the existing query, form1SubmitToProducts
, and change the action type to bulk upsert via primary key. This action requires a primary key column so the query knows which record to update. This should be a unique identifier to avoid incorrect changes. In this case, set the value to id
.
When the form is submitted, the query looks for an existing record using the provided ID. If there's a match, that record is updated. If not, the query creates a new record instead.
Include the form data
The form data isn't included in the new action type. Set the array of records to update to {{ [form1.data] }}
. Note that the form data is wrapped in brackets to provide it as an Object.
Refresh the table after submission
You can create an event handler to refresh the table to show the changes automatically:
- Add a new event handler for a Success event.
- Select Trigger query as the action to perform.
- Select query1.
Clear the form
To clear values from the form after submissions, enable Reset after successful submit in the Interaction section of the form's Inspector. This setting resets the values to those in the form's Data source field.
Increment IDs automatically
The form currently allows users to specify an ID. Since this form also creates and updates records, users could accidentally overwrite a record if they provide an existing ID. Instead, you should automatically increment the ID and prevent users from providing one in the form.
The following guidance is provided for demonstration purposes. Retool recommends using your database's auto-increment feature to create unique identifiers automatically.
For this guide, use Math
to find the highest ID number and use it to increment to the next ID automatically:
Math.max(...query1.data.id) + 1;
First, disable the ID input by setting the value for Disabled to true
in the Interaction section of the Inspector. Next, update the form's Initial data to provide a new ID if a row isn't selected:
{
{
table1.selectedRow
? table1.selectedRow
: { id: (Math.max(...query1.data.id) + 1).toString() };
}
}
Display image preview
The Form component can contain any other components, not just inputs. You can include an optional image preview using the provided image URL.
Add toggle
- Drag a Toggle Link component and position it below the input fields. This toggle is used to show or hide the image preview.
- Update the value for Text to
{{ self.value ? 'Hide' : 'Show' }} image preview
. - Set the value for Disabled using the value of the image URL input, such as
{{ !textInput2.value }}
. This disables the toggle if the input doesn't have a value.
Toggle Link has a value of false
when in a closed state and displays the text Show image preview.
Add image
- Drag an Image component and position it below the toggle.
- Set the Image source using the value of the input, such as
{{ textInput2.value }}
. - Set the value for Hidden to
{{ !toggleLink1.value || toggleLink1.disabled }}
. This hides the image preview if Toggle Link is either disabled or returns a value offalse
.
The image preview can now be toggled but is hidden automatically if no image URL is present.
Set the form title
Update the form's title so it's clear to the user if they are creating a record or updating an existing one. Select the form's title and change the Value:
#### {{ table1.selectedRow ? 'Edit' : 'Create new' }} product
This displays either Edit product or Create new product depending on whether a table row is selected or not.
Wrap up
Your form is now ready to use. Try it out and create a record, or select an existing record and update it.