Customize form inputs
In this guide, you will learn how to customize connected forms that are generated by running npx ampx generate forms
. Before you begin you will need:
- Your cloud sandbox with an Amplify Data resource up and running (npx ampx sandbox)
- A frontend application that has generated a connected form
All Amplify forms are built with the Amplify UI library. The generated form provides a mechanism to override properties for each individual input component, like TextField, TextAreaField, SelectField. You can override any props to those components with the overrides
prop on the form component. For example, if you want to change the variation and label of the content
field in the TodoCreateForm:
import TodoCreateForm from '@/ui-components/TodoCreateForm'
<TodoCreateForm overrides={{ content: { variation: 'quiet', label: 'Todo' } }}/>
You own updating the code directly for the generated form. Here's how you can customize the form.
Manually add form input field
You can manually add a form input connected to a data model to the generated form. For example, let's say you add a priority
field to your data model. Make the following edits to the generated form:
// 1. Set initialValues const initialValues = { content: "", priority: "" // Initial value for priority };
// 2. State setup const [priority, setPriority] = React.useState(initialValues.priority);
// 3. Update resetValues const resetStateValues = () => { .. // previous fields setPriority(initialValues.priority) setErrors({}); };
// 4. Validation setup const validations = { content: [], priority: [] // Assuming no special validations for now };
// 5. Update form submission onSubmit={async (event) => { event.preventDefault(); let modelFields = { .., priority };
// 6. Add TextField <TextField label="Priority" isRequired={false} isReadOnly={false} value={priority} onChange={(e) => { let { value } = e.target; if (onChange) { const modelFields = { priority: value, }; const result = onChange(modelFields); value = result?.priority ?? value; } if (errors.priority?.hasError) { runValidationTasks("priority", value); } setPriority(value); }} onBlur={() => runValidationTasks("priority", priority)} errorMessage={errors.priority?.errorMessage} hasError={errors.priority?.hasError} {...getOverrideProps(overrides, "priority")} />
Manually add option fields
Select Fields, Radio Group Fields, and Autocomplete Fields require a set of options for your users to choose from. For example, a "Status" input can only have the options "Not started", "In progress", and "Done". This would be identical to the above 6 steps, but in step 6 you would replace <TextField>
with <SelectField>
// 6. Import <SelectField> component and add to form return <SelectField label="Label" placeholder="Please select an option" value={status} onChange={(e) => { let { value } = e.target; if (onChange) { const modelFields = { status: value }; const result = onChange(modelFields); value = result?.status ?? value; } if (errors.status?.hasError) { runValidationTasks("status", value); } setStatus(value); }} onBlur={() => runValidationTasks("status", status)} errorMessage={errors.status?.errorMessage} hasError={errors.status?.hasError} {...getOverrideProps(overrides, "status")} > <option children="Not started" value="Not started" {...getOverrideProps(overrides, "statusOption0")}></option> <option children="In progress" value="In progress" {...getOverrideProps(overrides, "statusOption1")}></option> <option children="Done" value="Done" {...getOverrideProps(overrides, "statusOption2")}></option> </SelectField>
Configure form spacings (paddings and gaps)
Add spacing to your form and between inputs. Spacing values can either be a CSS length value (px
, rem
, em
, %
) or a reference to your theme object's spacing value (xss
, medium
, large
).
import TodoCreateForm from '@/ui-components/TodoCreateForm'
<TodoCreateForm overrides={{ TodoCreateForm: { rowGap: 'xl', // horizontal gap between inputs columnGap: 'xs', // vertical gap between inputs padding: 'xl', // padding around form },}} />
Customize label for Submit and Clear buttons
You can customize action button labels to better describe your form's use case, such as changing Submit
to Create Todo
.
import TodoCreateForm from '@/ui-components/TodoCreateForm'
<TodoCreateForm overrides={{ ClearButton: { children: 'Close' }, SubmitButton: { children: 'Save todo' }}} />
Toggle visibility for Submit and Clear buttons
You can customize the visibility of action buttons to better accommodate your form's use case.
import TodoCreateForm from '@/ui-components/TodoCreateForm'
<TodoCreateForm overrides={{ ClearButton: { display: 'none' }, SubmitButton: { display: 'none' }}} />
If you hide all form action buttons, you can still leverage the onChange
event handler to self-manage the form lifecycle. This is useful for a form that updates data in real-time without explicit user confirmation.
import TodoCreateForm from '@/ui-components/TodoCreateForm'
<TodoCreateForm onChange={(fields) => { console.log({ fields }) // make sure you return fields! return fields }}/>