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, Ark 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>Username</FieldLabel>
<Input {...field} className="h-9" 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>Password</FieldLabel>
<Input
{...field}
className="h-9"
placeholder="********"
type="password"
/>
<FieldError className="text-xs">
{fieldState.error?.message}
</FieldError>
</Field>
{/* 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. Field links each FieldLabel to its input, so there are no ids.
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}. The rest is on the Field page.
Input
Sets field, placeholder="johndoe", placeholder="********" and type="password". The rest is on the Input page.
Button
Sets type="submit". The rest is on the Button page.





