Prompt
build a form in react
Latest observation
Building a form in React depends on your use case. Below are two standard approaches: a vanilla React version using controlled state (best for simple forms) and an industry-standard production setup using React Hook Form + Zod (best for scalable, performant validation). Method 1: Vanilla React (Controlled Form)This approach uses standard useState hooks to manage input data. It is ideal for small forms where you don't want external dependencies. JavaScriptimport { useState } from 'react';
export default function BasicForm() {
const [formData, setFormData] = useState({
- name: '',
- email: '',
- role: 'developer',
});
const [errors, setErrors] = useState({});
const [submitted, setSubmitted] = useState(false);
// Validate fields on submission
const validate = () => {
const newErrors = {};
if (!formData.name.trim()) newErrors.name = 'Name is required';
if (!formData.email.trim()) {
newErrors.email = 'Email is required';
} else if (!/\S+@\S+.\S+/.test(formData.email)) {
newErrors.email = 'Invalid email address';
}
return newErrors;
};
const handleChange = (e) => {
const { name, value } = e.target;
- setFormData((prev) => ({ ...prev, [name]: value }));
};
const handleSubmit = (e) => {
e.preventDefault(); // Prevent full page reload
const validationErrors = validate();
if (Object.keys(validationErrors).length > 0) {
setErrors(validationErrors);
setSubmitted(false);
} else {
setErrors({});
setSubmitted(true);
console.log('Form Submitted Successfully:', formData);
}
};
return (
- <div style={{ maxWidth: '400px', margin: '2rem auto', fontFamily: 'sans-serif' }}>
<h2>Contact Us</h2>
- {submitted && <p style={{ color: 'green' }}>Form submitted successfully!</p>}
<form onSubmit={handleSubmit} noValidate>
{/* Name Field */}
- <div style={{ marginBottom: '1rem' }}>
- <label htmlFor="name" style={{ display: 'block', marginBottom: '.5rem' }}>Name</label>
<input
id="name"
type="text"
name="name"
value={formData.name}
onChange={handleChange}
- style={{ width: '100%', padding: '0.5rem' }}
/>
- {errors.name && <span style={{ color: 'red', fontSize: '0.85rem' }}>{errors.name}</span>}
</div>
{/* Email Field */}
- <div style={{ marginBottom: '1rem' }}>
- <label htmlFor="email" style={{ display: 'block', marginBottom: '.5rem' }}>Email</label>
<input
id="email"
type="email"
name="email"
value={formData.email}
onChange={handleChange}
- style={{ width: '100%', padding: '0.5rem' }}
/>
- {errors.email && <span style={{ color: 'red', fontSize: '0.85rem' }}>{errors.email}</span>}
</div>
{/* Role Select Dropdown */}
- <div style={{ marginBottom: '1rem' }}>
- <label htmlFor="role" style={{ display: 'block', marginBottom: '.5rem' }}>Role</label>
<select
id="role"
name="role"
value={formData.role}
onChange={handleChange}
- style={{ width: '100%', padding: '0.5rem' }}
>
<option value="developer">Developer</option>
<option value="designer">Designer</option>
<option value="manager">Manager</option>
</select>
</div>
- <button type="submit" style={{ padding: '0.5rem 1rem', cursor: 'pointer' }}>
Submit
</button>
</form>
</div>
);
}
- Method 2: Enterprise Ready (React Hook Form + Zod)For larger forms, managing state per keystroke can cause unnecessary re-renders. Modern React applications typically combine React Hook Form with Zod schema validation. 1. InstallationBashnpm install react-hook-form zod @hookform/resolvers
2. Form ComponentTypeScriptimport React from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
// Define schema with validation rules
const formSchema = z.object({
- username: z.string().min(3, 'Username must be at least 3 characters'),
- email: z.string().email('Please enter a valid email address'),
- password: z.string().min(8, 'Password must be at least 8 characters'),
});
type FormData = z.infer<typeof formSchema>;
export default function ZodForm() {
const {
register,
handleSubmit,
- formState: { errors, isSubmitting },
} = useForm<FormData>({
- resolver: zodResolver(formSchema),
});
- const onSubmit = async (data: FormData) => {
// Simulate API call
await new Promise((resolve) => setTimeout(resolve, 1000));
console.log('Valid Form Data:', data);
};
return (
<form onSubmit={handleSubmit(onSubmit)} style={{ maxWidth: '400px', margin: '2rem auto' }}><div>
<label>Username</label>
<input {...register('username')} />
- {errors.username && <p style={{ color: 'red' }}>{errors.username.message}</p>}
</div>
<div>
<label>Email</label>
<input type="email" {...register('email')} />
- {errors.email && <p style={{ color: 'red' }}>{errors.email.message}</p>}
</div>
<div>
<label>Password</label>
<input type="password" {...register('password')} />
- {errors.password && <p style={{ color: 'red' }}>{errors.password.message}</p>}
</div>
<button type="submit" disabled={isSubmitting}>
- {isSubmitting ? 'Submitting...' : 'Submit'}
</button>
</form>
);
}
- Best Practices to FollowPrevent Default Reload: Always call e.preventDefault() inside submit handlers when using standard forms to prevent full browser reloads.Label Association: Bind inputs using htmlFor="id" on <label> elements and matching id="id" on inputs for accessibility.Disable Submission State: Disable the submit button during API requests (isSubmitting) to prevent duplicate payloads.Controlled vs. Uncontrolled: Use useState when input values drive other UI components in real-time. Use react-hook-form (uncontrolled under the hood) when optimizing performance for complex forms.
Observation history
See 2 earlier observations
Create a free Obsurfable account to unlock historical responses, model comparisons, and deeper brand intelligence.
How did Obsurfable measure this prompt?
Obsurfable records AI answers to buyer-style prompts in its research corpus (3 observations for this page). Metrics are distributions over observations, not a single static ranking.
Which AI systems does Obsurfable collect answers from?
OpenAI, ChatGPT, Google, Gemini, Google AI Mode, Anthropic, Claude, Perplexity, Grok, DeepSeek, Mistral, Copilot, and Meta AI.