NimUI
ComponentsForms

Form

Styled form wrapper component for consistent form layouts and structure

The Form component is a lightweight wrapper around the native HTML <form> element. It provides consistent styling, spacing, and structure for building forms. It extends all standard form attributes, so you can attach onSubmit, action, method, and any other native form props.

Import

import { Form } from '@nim-ui/components';

Usage

Basic Form
Code
<Form onSubmit={handleSubmit}>
  <FormField label="Name" name="name">
    <Input placeholder="Operations lead" />
  </FormField>
  <FormField label="Email" name="email">
    <Input type="email" placeholder="ops@example.com" />
  </FormField>
  <Button type="submit" variant="primary">
    Submit
  </Button>
</Form>

Form Layouts

Vertical Layout (Default)

Vertical Form Layout
Code
<Form onSubmit={handleSubmit}>
  <div className="grid gap-4 sm:grid-cols-2">
    <FormField label="First name" name="firstName">
      <Input placeholder="Nim" />
    </FormField>
    <FormField label="Last name" name="lastName">
      <Input placeholder="Team" />
    </FormField>
  </div>
  <FormField label="Email" name="email">
    <Input type="email" placeholder="ops@example.com" />
  </FormField>
  <FormField label="Message" name="message">
    <Textarea placeholder="Share the operational context..." rows={4} />
  </FormField>
  <Button type="submit" variant="primary">
    Send Message
  </Button>
</Form>

Inline Fields

Form with Inline Fields
Code
<Form onSubmit={handleSubmit}>
  <div className="grid gap-4 sm:grid-cols-2">
    <FormField label="First name" name="firstName">
      <Input placeholder="Nim" />
    </FormField>
    <FormField label="Last name" name="lastName">
      <Input placeholder="Team" />
    </FormField>
  </div>
  <FormField label="Email" name="email">
    <Input type="email" placeholder="ops@example.com" />
  </FormField>
  <Button type="submit" variant="primary">
    Create Account
  </Button>
</Form>

With Select and Checkbox

Complete Form
Code
<Form onSubmit={handleSubmit}>
  <FormField label="Full name" name="name">
    <Input placeholder="Nim Operations" />
  </FormField>
  <FormField label="Work email" name="email">
    <Input type="email" placeholder="ops@example.com" />
  </FormField>
  <div className="space-y-2">
    <label htmlFor="plan" className="block text-sm font-medium">
      Plan
    </label>
    <Select>
      <SelectTrigger id="plan" className="w-full">
        <SelectValue placeholder="Select plan" />
      </SelectTrigger>
      <SelectContent>
        <SelectItem value="personal">Personal</SelectItem>
        <SelectItem value="business">Business</SelectItem>
        <SelectItem value="enterprise">Enterprise</SelectItem>
      </SelectContent>
    </Select>
  </div>
  <Checkbox id="terms" label="I agree to the terms and conditions" />
  <Button type="submit" variant="primary" fullWidth>
    Sign Up
  </Button>
</Form>

With Validation Errors

Form with Errors

Please enter a valid email address

Password must be at least 8 characters

Code
<Form onSubmit={handleSubmit}>
  <FormField label="Email" name="email" error={errors.email}>
    <Input type="email" placeholder="ops@example.com" />
  </FormField>
  <FormField label="Password" name="password" error={errors.password}>
    <Input type="password" placeholder="Password" />
  </FormField>
  <Button type="submit" variant="primary" fullWidth>
    Log In
  </Button>
</Form>

Props

The Form component extends React.FormHTMLAttributes<HTMLFormElement>, so it accepts all standard HTML form attributes in addition to the following:

NameTypeDefaultDescription
onSubmit(event: React.FormEvent<HTMLFormElement>) => void-Submit event handler. Call event.preventDefault() to handle submission in JavaScript.
actionstring-URL to submit the form to when using native form submission
method'get' | 'post'-HTTP method for native form submission
classNamestring-Additional CSS classes to apply to the form element
children*ReactNode-Form content including inputs, selects, buttons, and other form elements

Usage Examples

Login Form

Login Form Example

Operator console

Sign in

Use your workspace email to continue.

Use at least 8 characters.

Forgot password?
Code
import { useState } from 'react';
import { Form, FormField, Input, Button, Checkbox } from '@nim-ui/components';

function LoginForm() {
  const [loading, setLoading] = useState(false);
  const [errors, setErrors] = useState<Record<string, string>>({});

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);

    const formData = new FormData(e.currentTarget as HTMLFormElement);
    const email = formData.get('email') as string;
    const password = formData.get('password') as string;

    try {
      await login(email, password);
    } catch (err) {
      setErrors({ email: 'Invalid email or password' });
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="w-full max-w-sm rounded-md border border-neutral-200 bg-white p-6 shadow-soft">
      <div className="mb-5">
        <p className="text-xs font-medium uppercase text-neutral-500">Operator console</p>
        <h3 className="mt-1 text-xl font-semibold text-neutral-950">
          Sign in
        </h3>
        <p className="mt-1 text-sm text-neutral-600">Use your workspace email to continue.</p>
      </div>
      <Form onSubmit={handleSubmit} className="gap-5">
        <FormField label="Email" name="email" error={errors.email}>
          <Input
            name="email"
            type="email"
            placeholder="ops@example.com"
            autoComplete="email"
          />
        </FormField>
        <FormField label="Password" name="password" error={errors.password}>
          <Input
            name="password"
            type="password"
            placeholder="Password"
            autoComplete="current-password"
          />
        </FormField>
        <div className="flex flex-wrap items-center justify-between gap-3">
          <Checkbox id="remember" label="Keep me signed in" name="remember" />
          <a href="#" className="text-sm font-medium text-primary-700">
            Forgot password?
          </a>
        </div>
        <Button type="submit" variant="primary" fullWidth loading={loading}>
          Sign in
        </Button>
      </Form>
    </div>
  );
}

Contact Form

import {
  Form,
  FormField,
  Input,
  Textarea,
  Select,
  SelectTrigger,
  SelectValue,
  SelectContent,
  SelectItem,
  Button,
} from '@nim-ui/components';

function ContactForm() {
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    const formData = new FormData(e.currentTarget as HTMLFormElement);
    await sendContactMessage(Object.fromEntries(formData));
  };

  return (
    <Form onSubmit={handleSubmit} className="gap-5">
      <div className="grid gap-4 sm:grid-cols-2">
        <FormField label="First name" name="firstName">
          <Input name="firstName" placeholder="Nim" />
        </FormField>
        <FormField label="Last name" name="lastName">
          <Input name="lastName" placeholder="Team" />
        </FormField>
      </div>
      <FormField label="Email" name="email">
        <Input name="email" type="email" placeholder="ops@example.com" />
      </FormField>
      <div className="space-y-2">
        <label htmlFor="subject" className="block text-sm font-medium">
          Subject
        </label>
        <Select name="subject">
          <SelectTrigger id="subject" className="w-full">
            <SelectValue placeholder="What is this about?" />
          </SelectTrigger>
          <SelectContent>
            <SelectItem value="general">General Inquiry</SelectItem>
            <SelectItem value="support">Technical Support</SelectItem>
            <SelectItem value="billing">Billing</SelectItem>
            <SelectItem value="feedback">Feedback</SelectItem>
          </SelectContent>
        </Select>
      </div>
      <FormField label="Message" name="message">
        <Textarea name="message" placeholder="Your message..." rows={6} />
      </FormField>
      <Button type="submit" variant="primary">
        Send Message
      </Button>
    </Form>
  );
}

Multi-step Form

import { useState } from 'react';
import { Form, FormField, Input, Button } from '@nim-ui/components';

function MultiStepForm() {
  const [step, setStep] = useState(1);

  return (
    <Form onSubmit={handleFinalSubmit} className="gap-5">
      {step === 1 && (
        <>
          <FormField label="Full name" name="name">
            <Input name="name" placeholder="Nim Operations" />
          </FormField>
          <FormField label="Email" name="email">
            <Input name="email" type="email" placeholder="ops@example.com" />
          </FormField>
          <Button variant="primary" onClick={() => setStep(2)}>
            Next
          </Button>
        </>
      )}
      {step === 2 && (
        <>
          <FormField label="Company" name="company">
            <Input name="company" placeholder="Nim UI" />
          </FormField>
          <FormField label="Role" name="role">
            <Input name="role" placeholder="Operations lead" />
          </FormField>
          <div className="flex gap-4">
            <Button variant="outline" onClick={() => setStep(1)}>
              Back
            </Button>
            <Button type="submit" variant="primary">
              Submit
            </Button>
          </div>
        </>
      )}
    </Form>
  );
}

Accessibility

The Form component follows accessibility best practices:

  • Uses the semantic <form> HTML element
  • Supports native form validation attributes on child inputs
  • Works with screen readers by maintaining proper form landmark semantics
  • All child form elements should include associated labels (see FormField)
  • Error messages are announced to screen readers via aria-live regions
  • FormField - Labeled field wrapper with error and helper text
  • Input - Text input field
  • Select - Dropdown selection
  • Textarea - Multi-line text input
  • Checkbox - Boolean checkbox input
  • Button - Form submit button

On this page