Skip to content

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

Free

Bottom Drawer with Form for React

A bottom drawer titled Add New Contact, with name, email, and phone fields, plus Add Contact and Cancel.

Add New Contact slides up with Name, Email, and Phone fields, then Add Contact and Cancel. Email is an email field and Phone is a telephone field.

Use it for a short create flow on a phone. A longer form belongs on the page, or in a Dialog on a wide screen. In React, Base UI does not submit the contact.

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.

Anatomy

Drawer anatomy: grabber, title, description, content, close

Usage

<Drawer showSwipeHandle>
  <DrawerTrigger render={<Button variant="outline" />}>
    Add Contact
  </DrawerTrigger>
  <DrawerContent>
    <DrawerHeader>
      <DrawerTitle>Add New Contact</DrawerTitle>
      <DrawerDescription>
        Fill in the details below to add a new contact.
      </DrawerDescription>
    </DrawerHeader>
    <FieldGroup className="p-4">
      <Field>
        <FieldLabel htmlFor="contact-name">Name</FieldLabel>
        <Input id="contact-name" placeholder="Enter name" type="text" />
      </Field>
      <Field>
        <FieldLabel htmlFor="contact-email">Email</FieldLabel>
        <Input id="contact-email" placeholder="Enter email" type="email" />
      </Field>
      <Field>
        <FieldLabel htmlFor="contact-phone">Phone</FieldLabel>
        <Input
          id="contact-phone"
          placeholder="Enter phone number"
          type="tel"
        />
      </Field>
    </FieldGroup>
    <DrawerFooter>
      <Button>Add Contact</Button>
{/* The rest of the file is under Installation. */}

FAQ

Which fields does the form have?

Name, a text input; Email, type="email"; and Phone, type="tel". Each has a placeholder and sits in a Field inside a FieldGroup.

How are the labels tied to the inputs?

Each label and input share a Field, so the label names the input and clicking it focuses the field. The FieldLabel points at its input with htmlFor and a matching id.

Does Add Contact submit anything?

Not yet: the fields aren't in a form and the button has no handler. Wrap the fields in a form, give the button type="submit", and close the drawer once the contact is saved: Pass open to Drawer; onOpenChange receives the next boolean.

How does Cancel close the drawer?

It's a DrawerClose, so pressing it dismisses the drawer and drops what was typed. The Button goes in the render prop of DrawerClose.

Why do the inputs set a type?

type="email" and type="tel" bring up the email keyboard and the number pad on phones, and help the browser autofill. Name uses type="text".

How does Add Contact open the drawer?

An outline button opens the drawer. Its text, Add Contact, is the accessible name. The Button goes in the render prop of DrawerTrigger.

API Reference

Drawer

Sets showSwipeHandle. The rest is on the Drawer page.

Button

Sets variant="outline". The rest is on the Button page.

Field

Sets htmlFor="contact-name", htmlFor="contact-email" and htmlFor="contact-phone". The rest is on the Field page.

Input

Sets id="contact-name", placeholder="Enter name", type="text", id="contact-email", placeholder="Enter email" and type="email". The rest is on the Input page.