Form Components
Comprehensive form components with validation, accessibility, and interactive examples
5 Form ControlsValidationWCAG Compliant
Text Input Variants
Standard States
We'll never share your email with anyone else.
Validation States
Looks good!
Please review this field
This field is required
Textarea Component
This field is required
Select Dropdown
Please select an option
Selection Controls
Checkboxes
Radio Buttons
Choose your plan:
Disabled options:
Code Examples
Basic Input with Validation
import { Input, FormLabel, FormError } from '~/components/ui';
function MyForm() {
const [value, setValue] = useState('');
const [error, setError] = useState('');
const handleBlur = () => {
if (!value.trim()) {
setError('This field is required');
} else {
setError('');
}
};
return (
<div>
<FormLabel htmlFor="input" required>
Input Label
</FormLabel>
<Input
id="input"
value={value}
onChange={(e) => setValue(e.target.value)}
onBlur={handleBlur}
error={error}
placeholder="Enter text..."
/>
{error && <FormError>{error}</FormError>}
</div>
);
}Basic form input with label, validation, and error handling
Form Validation Hook
import { useState, useEffect } from 'react';
import { Input, FormLabel } from '~/components/ui';
function useFormValidation(initialValue: string, validator?: (value: string) => string | null) {
const [value, setValue] = useState(initialValue);
const [error, setError] = useState<string | null>(null);
const [touched, setTouched] = useState(false);
const handleChange = (newValue: string) => {
setValue(newValue);
if (touched && validator) {
setError(validator(newValue));
}
};
const handleBlur = () => {
setTouched(true);
if (validator) {
setError(validator(value));
}
};
return { value, error, touched, handleChange, handleBlur };
}
function MyForm() {
const email = useFormValidation('', (value) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return value && !emailRegex.test(value) ? 'Invalid email' : null;
});
return (
<div>
<FormLabel htmlFor="email">Email</FormLabel>
<Input
id="email"
value={email.value}
onChange={(e) => email.handleChange(e.target.value)}
onBlur={email.handleBlur}
error={email.error || undefined}
/>
</div>
);
}Custom hook for form validation with reusable logic
Complete Form with State
import { useState } from 'react';
import { Input, Textarea, Select, Checkbox } from '~/components/ui';
interface FormData {
name: string;
email: string;
message: string;
priority: string;
newsletter: boolean;
}
function ContactForm() {
const [formData, setFormData] = useState<FormData>({
name: '',
email: '',
message: '',
priority: 'medium',
newsletter: false
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
console.log('Form submitted:', formData);
// Handle form submission
};
const updateField = (field: keyof FormData, value: string | boolean) => {
setFormData(prev => ({ ...prev, [field]: value }));
};
return (
<form onSubmit={handleSubmit} className="space-y-6">
<Input
label="Name"
value={formData.name}
onChange={(e) => updateField('name', e.target.value)}
required
/>
<Input
label="Email"
type="email"
value={formData.email}
onChange={(e) => updateField('email', e.target.value)}
required
/>
<Select
label="Priority"
value={formData.priority}
onChange={(e) => updateField('priority', e.target.value)}
>
<option value="low">Low</option>
<option value="medium">Medium</option>
<option value="high">High</option>
<option value="urgent">Urgent</option>
</Select>
<Textarea
label="Message"
value={formData.message}
onChange={(e) => updateField('message', e.target.value)}
rows={4}
/>
<Checkbox
label="Subscribe to newsletter"
checked={formData.newsletter}
onChange={(checked) => updateField('newsletter', checked)}
/>
<button
type="submit"
className="w-full px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
>
Send Message
</button>
</form>
);
}Complete form implementation with TypeScript interfaces and state management
Form Best Practices
✅ Do's
- Use clear, descriptive labels for all form fields
- Provide helpful placeholder text and helper messages
- Show validation errors immediately when fields are touched
- Use proper input types (email, password, tel, etc.)
- Group related fields and use logical tab order
❌ Don'ts
- Don't rely on placeholder text as the only label
- Avoid showing all validation errors at once initially
- Don't disable form submission without clear indication
- Avoid overly complex validation that frustrates users
- Don't break the expected tab order for accessibility