Skip to content

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

Free

Compact Form for React

A compact sign-in form: short username and password fields, tight gaps, and a full-width Sign In button.

Username and password sit close together, with shorter fields and smaller error text. Username needs 2 characters and password needs 8. Sign In stretches the full width of the narrow form.

Put it in a sidebar, a popover, or a small dialog. A roomier page can keep the default Field spacing. In React, Base UI does not tighten the gaps. The classes do.

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.
Use email insteadNo credit card

Usage

<form className="w-full max-w-sm" onSubmit={form.handleSubmit(onSubmit)}>
  <FieldGroup className="gap-3">
    <Controller
      control={form.control}
      name="username"
      render={({ field, fieldState }) => (
        <Field className="gap-1.5" invalid={fieldState.invalid}>
          <FieldLabel htmlFor="compact-form-username">Username</FieldLabel>
          <Input
            {...field}
            className="h-9"
            id="compact-form-username"
            placeholder="johndoe"
          />
          <FieldError className="text-xs">
            {fieldState.error?.message}
          </FieldError>
        </Field>
      )}
    />
    <Controller
      control={form.control}
      name="password"
      render={({ field, fieldState }) => (
        <Field className="gap-1.5" invalid={fieldState.invalid}>
          <FieldLabel htmlFor="compact-form-password">Password</FieldLabel>
          <Input
            {...field}
            className="h-9"
            id="compact-form-password"
            placeholder="********"
{/* The rest of the file is under Installation. */}

FAQ

What makes this form compact?

The FieldGroup is gap-3 and each Field is gap-1.5, so label, input and error sit close together. Both inputs are h-9, both FieldErrors are text-xs, and the form is max-w-sm.

What do username and password have to satisfy?

username is z.string().min(2) and password is z.string().min(8). Neither passes a custom message, so FieldError shows Zod's default text, such as Too small: expected string to have >=2 characters.

How is the password field different from username?

Its Input sets type="password" and the placeholder ********. Username is a text input with the placeholder johndoe. Both spread the Controller's field. Each FieldLabel points at its input with htmlFor, such as compact-form-password.

How is Sign In sized?

Sign In is a type="submit" button with h-9 w-full, so it matches the input height and spans the column.

What are the starting values?

defaultValues sets username and password to empty strings, so an empty submit fails both minimums and shows both errors.

When do those minimums run?

mode is unset, so React Hook Form runs the Zod resolver when Sign In submits, then re-checks a field as you fix it. Once both pass, onSubmit logs the values.

API Reference

Field

Sets invalid={fieldState.invalid}, htmlFor="compact-form-username" and htmlFor="compact-form-password". The rest is on the Field page.

Input

Sets field, id="compact-form-username", placeholder="johndoe", id="compact-form-password", placeholder="********" and type="password". The rest is on the Input page.

Button

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