Skip to content

shadcn.io is an independent project built on shadcn/ui

Free

Form with Optional Fields for React

Required first name, last name, and email, plus company and website marked optional in their labels.

First and last name share a row and need 2 characters. Email must be an address. Company can be blank. Website can be blank too, but a filled website must be a valid URL.

Use it when some answers are nice to have and the rest are not. Marking nothing optional forces every Input. In React, Base UI does not treat a field as optional.

Preview

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

Usage

<form className="w-full max-w-md" onSubmit={form.handleSubmit(onSubmit)}>
  <FieldGroup>
    <div className="grid grid-cols-2 gap-4">
      <Controller
        control={form.control}
        name="firstName"
        render={({ field, fieldState }) => (
          <Field invalid={fieldState.invalid}>
            <FieldLabel htmlFor="form-with-optional-fields-first-name">
              First Name
            </FieldLabel>
            <Input
              {...field}
              id="form-with-optional-fields-first-name"
              placeholder="John"
            />
            <FieldError>{fieldState.error?.message}</FieldError>
          </Field>
        )}
      />
      <Controller
        control={form.control}
        name="lastName"
        render={({ field, fieldState }) => (
          <Field invalid={fieldState.invalid}>
            <FieldLabel htmlFor="form-with-optional-fields-last-name">
              Last Name
            </FieldLabel>
            <Input
              {...field}
              id="form-with-optional-fields-last-name"
{/* The rest of the file is under Installation. */}

FAQ

Which fields are required?

firstName and lastName need at least 2 characters, with "First name must be at least 2 characters." and "Last name must be at least 2 characters." email is z.email(…) with "Please enter a valid email address."

Why can company be left blank?

company is z.string().optional() with no length rule, so an empty string passes. Its label reads Company (Optional) and its description asks "Where do you work?"

What website values pass?

website is z.url().optional().or(z.literal("")): an empty string or a full URL such as https://example.com. Anything else gets Zod's default URL message.

Which fields have a description?

Company ("Where do you work?") and website ("Your personal or company website."). The required fields have a label, the input and a FieldError.

How are the optional inputs registered?

Like the others: a Controller per field, the input takes field, and the Field gets invalid={fieldState.invalid}. defaultValues starts every field at an empty string. Each label's htmlFor matches its input's id, such as form-with-optional-fields-website.

What does Save log?

Save is a type="submit" button. Once the required fields pass, onSubmit logs all five values, with empty strings for skipped optional fields.

API Reference

Field

Sets invalid={fieldState.invalid}, htmlFor="form-with-optional-fields-first-name", htmlFor="form-with-optional-fields-last-name", htmlFor="form-with-optional-fields-email", htmlFor="form-with-optional-fields-company" and htmlFor="form-with-optional-fields-website". The rest is on the Field page.

Input

Sets field, id="form-with-optional-fields-first-name", placeholder="John", id="form-with-optional-fields-last-name", placeholder="Doe" and id="form-with-optional-fields-email". The rest is on the Input page.

Button

Sets type="submit". The rest is on the Button page.