Form

Renders a <form> and provides form-wide field defaults through FormContext.

Renders a <form> and provides form-wide field defaults through FormContext. It is the lowest priority in the override chain - a FormControl or an explicit prop on a control always wins.

Architecture: Form is purely presentational + context. It holds no form state, runs no validation, and is not tied to any form library - bridging to a specific one (e.g. TanStack Form's Field) is left to the consuming app. Pass onSubmit straight through; wire it to your form library's submit handler (e.g. form.handleSubmit()).

Examples

Default

We'll never share it.

const args: Partial<FormProps> = { size: 'md', color: 'primary', fullWidth: true }

<Form {...args} onSubmit={(event) => event.preventDefault()}>
  <Flex flexDirection="column" gap={4} maxWidth="420px">
    <FormControl>
      <Flex flexDirection="column" gap={1} alignItems="flex-start">
        <FormLabel>Name</FormLabel>
        <TextInput variant="outlined" placeholder="John Smith" />
      </Flex>
    </FormControl>
    <FormControl>
      <Flex flexDirection="column" gap={1} alignItems="flex-start">
        <FormLabel>Email</FormLabel>
        <TextInput variant="outlined" placeholder="[email protected]" />
        <FormHelperText>We'll never share it.</FormHelperText>
      </Flex>
    </FormControl>
  </Flex>
</Form>

Every Input

A line of text.

Type to find a city.

Typed or stepped, from 0 to 10.

Choices
Chosen
const args: Partial<FormProps> = { size: 'md', color: 'primary', fullWidth: true }

<Form {...args} onSubmit={(event) => event.preventDefault()}>
  <Flex flexDirection="column" gap={4} maxWidth="520px">
    <FormControl>
      <FormLabel>Text</FormLabel>
      <TextInput variant="outlined" placeholder="John Smith" />
      <FormHelperText>A line of text.</FormHelperText>
    </FormControl>
    <FormControl>
      <FormLabel>City</FormLabel>
      <Autocomplete
        variant="outlined"
        options={['Berlin', 'Lisbon', 'Oslo', 'Rome']}
        placeholder="Search a city"
        noOptionsText="No city matches"
        clearLabel="Clear"
        openLabel="Open"
        closeLabel="Close"
      />
      <FormHelperText>Type to find a city.</FormHelperText>
    </FormControl>
    <FormControl>
      <FormLabel>Number</FormLabel>
      <NumberInput
        variant="outlined"
        defaultValue={3}
        min={0}
        max={10}
        incrementLabel="Increase"
        decrementLabel="Decrease"
      />
      <FormHelperText>Typed or stepped, from 0 to 10.</FormHelperText>
    </FormControl>
    <FormControl>
      <FormLabel>Native select</FormLabel>
      <NativeSelect variant="outlined" options={platformOptions} placeholder="Platform" />
    </FormControl>
    <FormControl>
      <FormLabel>Select</FormLabel>
      <Select variant="outlined" placeholder="Platform">
        {platformOptions.map((option) => (
          <MenuItem key={option.value} value={option.value}>
            {option.label}
          </MenuItem>
        ))}
      </Select>
    </FormControl>
    <FormControl>
      <FormLabel>Range</FormLabel>
      <RangeInput defaultValue={30} valueLabel="auto" />
    </FormControl>
    <FormControl>
      <FormLabel>Rating</FormLabel>
      <Rating defaultValue={3} />
    </FormControl>
    <FormControl>
      <FormLabel>Transfer</FormLabel>
      <TransferList
        items={fruits}
        defaultValue={['cherry']}
        leftLabel="Choices"
        rightLabel="Chosen"
        moveRightLabel="Move right"
        moveLeftLabel="Move left"
      />
    </FormControl>
    <Flex flexDirection="column" gap={1}>
      <Checkbox id="every-input-checkbox">Checkbox</Checkbox>
      <Plans />
      <Switch id="every-input-switch">Switch</Switch>
    </Flex>
    <Button type="submit">Submit</Button>
  </Flex>
</Form>