shadcn.io is an independent project built on shadcn/ui
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.
Installation
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.
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.





