Bluewoo HRMS
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

ElementSpacing
Between fieldsspace-y-6
Label to inputspace-y-2
Grid columnsgap-6
Button groupgap-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>