Design SystemComponents
Forms
Input, select, and form patterns
Form Components
Form styling patterns for HRMS.
Input
<Input
type="text"
placeholder="Enter name..."
className="bg-background"
/>Input Styling
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm"Label
<Label htmlFor="email">Email</Label>Label Styling
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"Form Field Pattern
Use this pattern for all form fields:
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
placeholder="john@example.com"
/>
<p className="text-sm text-muted-foreground">
We'll never share your email.
</p>
</div>Select
<Select>
<SelectTrigger className="w-full">
<SelectValue placeholder="Select department" />
</SelectTrigger>
<SelectContent>
<SelectItem value="engineering">Engineering</SelectItem>
<SelectItem value="design">Design</SelectItem>
<SelectItem value="product">Product</SelectItem>
</SelectContent>
</Select>Checkbox
<div className="flex items-center space-x-2">
<Checkbox id="terms" />
<Label htmlFor="terms" className="text-sm font-normal">
Accept terms and conditions
</Label>
</div>Switch
<div className="flex items-center space-x-2">
<Switch id="notifications" />
<Label htmlFor="notifications">Enable notifications</Label>
</div>Textarea
<Textarea
placeholder="Type your message..."
className="min-h-[100px] resize-none"
/>Form with React Hook Form
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import * as z from "zod";
const formSchema = z.object({
name: z.string().min(2, "Name must be at least 2 characters"),
email: z.string().email("Invalid email address"),
department: z.string().min(1, "Please select a department"),
});
export function EmployeeForm() {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
name: "",
email: "",
department: "",
},
});
function onSubmit(values: z.infer<typeof formSchema>) {
console.log(values);
}
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl>
<Input placeholder="John Doe" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input type="email" placeholder="john@example.com" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="department"
render={({ field }) => (
<FormItem>
<FormLabel>Department</FormLabel>
<Select onValueChange={field.onChange} defaultValue={field.value}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="Select department" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="engineering">Engineering</SelectItem>
<SelectItem value="design">Design</SelectItem>
<SelectItem value="product">Product</SelectItem>
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
</form>
</Form>
);
}Form Inside Content Card
<ContentCard title="Add New Employee">
<form className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<Label>First Name</Label>
<Input placeholder="John" />
</div>
<div className="space-y-2">
<Label>Last Name</Label>
<Input placeholder="Doe" />
</div>
</div>
<div className="space-y-2">
<Label>Email</Label>
<Input type="email" placeholder="john.doe@company.com" />
</div>
<div className="space-y-2">
<Label>Department</Label>
<Select>
<SelectTrigger>
<SelectValue placeholder="Select department" />
</SelectTrigger>
<SelectContent>
<SelectItem value="engineering">Engineering</SelectItem>
<SelectItem value="design">Design</SelectItem>
</SelectContent>
</Select>
</div>
<div className="flex justify-end gap-3">
<Button variant="outline">Cancel</Button>
<Button>Create Employee</Button>
</div>
</form>
</ContentCard>Form Spacing Rules
| Element | Spacing |
|---|---|
| Between fields | space-y-6 |
| Label to input | space-y-2 |
| Grid columns | gap-6 |
| Button group | gap-3 |
Error States
<div className="space-y-2">
<Label htmlFor="email" className="text-destructive">Email</Label>
<Input
id="email"
type="email"
className="border-destructive focus-visible:ring-destructive"
/>
<p className="text-sm text-destructive">
Please enter a valid email address.
</p>
</div>