Create forms using the Form component

Use the Form component to build a form that creates and updates records.

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 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 new record or update existing data by selecting a record from a table and populating the form. The form also increments IDs automatically.

📘

If you're not sure whether to use Form or JSON Schema Form, learn more about building forms on Retool and compare their features.


Demo

Try out the app to see the form in action (submissions are disabled).

Generate the inputs

First, create a new app. Retool automatically adds a table (table1) and query (query1) to your app to display products table records from the sample onboarding_db PostgreSQL database. Next, drag a Form component onto the canvas and place it next to the table. New forms are initially empty so you need to add inputs or generate a new form.

Click generate from a resource, then select the onboarding_db database and products table. The form generator displays the column names from the selected table and the generated input fields. Retool evaluates the type of each column to determine the input type to use. For instance, an Integer column results in a Number Input.

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.

Update the labels for each input and set the fields required to be Name, Created at, Updated at, and ID fields.

Click Generate form to create the new form.

Each input is generated with a value for form data key—shown in the Advanced 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 depending on its purpose. Validation for a selected input is configured in the Validation section of the Inspector.

Validation supports options like pattern matching (URL, email, or regular expression) or minimum and maximum lengths. Select the Image URL input and change the pattern to URL so that invalid URL formats produce a validation error.


Submit the form to create a record

Retool also generates a query, form1SubmitToProducts, to create new records on the database when the form is submitted.

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.


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 Initial data 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.data ? table1.selectedRow.data : null;
  }
}

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:

  1. Add a new event handler for a Success event
  2. Select Trigger query as the action to perform
  3. Select query1


Clear the form

There are two options for clearing values from the form:

  • Add a button to the table that clears the selected row: Enable Show a button to clear selection in the Selected Rows section of the Inspector.
  • Clear the form on submission: Enable Reset after submit in the Basic section of the Inspector.

Increment IDs automatically

The form currently allows users to specify an ID. Since this form will create or update records, users could accidentally overwrite an existing record if they provided 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. We strongly recommend using your database's auto-increment feature to create unique identifiers automatically.

For this guide, you can use Math to find the highest ID number from a set of data and use it to increment to the next ID to use 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.data
      ? table1.selectedRow.data
      : { 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

  1. Drag a Toggle Link component and position it below the input fields. This toggle is used to show or hide the image preview.
  2. Update the value for Text to {{ self.value ? 'Hide' : 'Show' }} image preview.
  3. 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

  1. Drag an Image component and position it below the toggle.
  2. Set the Image source using the value of the input, such as {{ textInput2.value }}.
  3. 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 of false.

The image preview can now be toggled but is hidden automatically if no image URL is present.


Set the form title

The final step is to update the form's title so it's clear to the user if they are creating a new record or updating an existing one. Select the form's title and change the Value:

#### {{ table1.selectedRow.data ? 'Edit' : 'Create new' }} product

This displays either Edit product or Create new product depending on whether a table row is currently selected or not.

Wrap up

Your form is now ready to use. Try it out and create a new record, or select an existing record and update it.


What’s Next

Learn more about forms, the Form component, or creating forms using JSON Schema Form.