Skip to content

Lesson 4 of 6

Forms and state

Let native controls send values, and decide who remembers a component’s current state.

Name values that a form should send

A form only sends a control when it has a name. Put name on native inputs, checkboxes, and form-enabled picker roots. For example, Select uses its name to create a visually hidden native select proxy for submission.

Add thistsx
<form>
  <Input name="email" type="email" />
  <Select name="size" defaultValue="small">
    <Label>Size</Label>
    <SelectTrigger><SelectValue /></SelectTrigger>
    <SelectPopover>...</SelectPopover>
  </Select>
</form>

Add a value by pressing Enter

An input beside a submit button is just a form. A text input and a Button with type="submit" share one form, so pressing Enter in the field and pressing the button both fire the form's onSubmit — you never write a key handler for it. Give the Input a name, read that value from the submit event, then reset the form for the next entry. This is the whole “add item” field, composed from pieces you already have.

Add thistsx
<form
  onSubmit={(event) => {
    event.preventDefault();
    const form = event.currentTarget;
    onAdd(String(new FormData(form).get("item")));
    form.reset();
  }}
>
  <TextField>
    <Label>New item</Label>
    <Input name="item" placeholder="Add an item" />
  </TextField>
  <Button type="submit">Add</Button>
</form>

Control state when your app needs to know now

Use value with onChange when your app owns a selected value. Use open with onToggle when your app owns whether an overlay is open. The component asks for a change, and your state gives it the new value back.

Add thistsx
const [open, setOpen] = useState(false);

<Dialog open={open} onToggle={setOpen}>...</Dialog>

Use a default for a starting value

Use defaultValue, defaultSelected, or defaultOpen when the component may remember its own state after the first render. This is simpler for a small form that does not need live app state. Do not pass both a controlled value and expect a default to keep changing it later.

Add thistsx
<Checkbox defaultSelected>Send me updates</Checkbox>
<Accordion defaultValue="shipping">...</Accordion>