Usage in React
This guide shows you how to use Forms in React web applications, including setup, configuration, and best practices for web development.
React Setup
Basic React Integration
🌐 React Integration
Forms integrates seamlessly with React web applications using the Form component:
import React from 'react';
import { Form, useFormField, useFormContext } from '@mapples/form';
const LoginForm = () => {
const onSubmit = (data) => {
console.log('Form submitted:', data);
};
return (
<Form
initialValues={{ email: '', password: '' }}
onSubmit={onSubmit}
>
<EmailField />
<PasswordField />
<SubmitButton />
</Form>
);
};
const EmailField = () => {
const {
value,
error,
setValue,
touch
} = useFormField('email', '');
return (
<div>
<label htmlFor="email">Email</label>
<input
value={value || ''}
onChange={(e) => setValue(e.target.value)}
onBlur={() => touch('email')}
type="email"
id="email"
placeholder="Enter your email"
/>
{error && (
<span className="error">{error}</span>
)}
</div>
);
};
const PasswordField = () => {
const {
value,
error,
setValue,
touch
} = useFormField('password', '');
return (
<div>
<label htmlFor="password">Password</label>
<input
value={value || ''}
onChange={(e) => setValue(e.target.value)}
onBlur={() => touch('password')}
type="password"
id="password"
placeholder="Enter your password"
/>
{error && (
<span className="error">{error}</span>
)}
</div>
);
};
const SubmitButton = () => {
const { submitForm } = useFormContext();
return (
<button type="submit" onClick={submitForm}>
Login
</button>
);
};
HTML Form Integration
🔗 HTML Forms
Forms works with standard HTML form elements and provides enhanced functionality:
import React from 'react';
import { Form, useFormField } from '@mapples/form';
const ContactForm = () => {
const onSubmit = (data) => {
console.log('Contact form submitted:', data);
};
return (
<Form
initialValues={{
name: '',
email: '',
message: '',
newsletter: false,
}}
onSubmit={onSubmit}
className="contact-form"
>
<NameField />
<EmailField />
<MessageField />
<NewsletterField />
<SubmitButton />
</Form>
);
};
const NameField = () => {
const nameField = useField('name', {
required: 'Name is required',
minLength: {
value: 2,
message: 'Name must be at least 2 characters',
},
});
return (
<div className="form-group">
<label htmlFor="name">Name</label>
<input
{...nameField}
type="text"
id="name"
placeholder="Your name"
/>
{nameField.error && (
<span className="error-message">{nameField.error}</span>
)}
</div>
);
};
const EmailField = () => {
const emailField = useField('email', {
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Invalid email address',
},
});
return (
<div className="form-group">
<label htmlFor="email">Email</label>
<input
{...emailField}
type="email"
id="email"
placeholder="your.email@example.com"
/>
{emailField.error && (
<span className="error-message">{emailField.error}</span>
)}
</div>
);
};
const MessageField = () => {
const messageField = useField('message', {
required: 'Message is required',
minLength: {
value: 10,
message: 'Message must be at least 10 characters',
},
});
return (
<div className="form-group">
<label htmlFor="message">Message</label>
<textarea
{...messageField}
id="message"
rows={5}
placeholder="Your message here..."
/>
{messageField.error && (
<span className="error-message">{messageField.error}</span>
)}
</div>
);
};
const NewsletterField = () => {
const newsletterField = useField('newsletter');
return (
<div className="form-group">
<label>
<input
{...newsletterField}
type="checkbox"
/>
Subscribe to newsletter
</label>
</div>
);
};
Advanced React Patterns
Custom Form Components
🎨 Custom Components
Create reusable form components for consistent styling and behavior:
import React from 'react';
import { useField } from '@mapples/form';
const FormField = ({ name, label, type = 'text', validation, ...props }) => {
const field = useField(name, validation);
return (
<div className="form-field">
<label htmlFor={name} className="form-label">
{label}
</label>
<input
{...field}
{...props}
type={type}
id={name}
className={`form-input ${field.error ? 'error' : ''}`}
/>
{field.error && (
<span className="form-error">{field.error}</span>
)}
</div>
);
};
const RegistrationForm = () => {
const { handleSubmit, formState } = useForm({
defaultValues: {
firstName: '',
lastName: '',
email: '',
password: '',
confirmPassword: '',
},
});
const onSubmit = (data) => {
console.log('Registration data:', data);
};
return (
<form onSubmit={handleSubmit(onSubmit)} className="registration-form">
<FormField
name="firstName"
label="First Name"
validation={{
required: 'First name is required',
minLength: {
value: 2,
message: 'First name must be at least 2 characters',
},
}}
/>
<FormField
name="lastName"
label="Last Name"
validation={{
required: 'Last name is required',
minLength: {
value: 2,
message: 'Last name must be at least 2 characters',
},
}}
/>
<FormField
name="email"
label="Email"
type="email"
validation={{
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Invalid email address',
},
}}
/>
<FormField
name="password"
label="Password"
type="password"
validation={{
required: 'Password is required',
minLength: {
value: 8,
message: 'Password must be at least 8 characters',
},
pattern: {
value: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/,
message: 'Password must contain uppercase, lowercase, and number',
},
}}
/>
<FormField
name="confirmPassword"
label="Confirm Password"
type="password"
validation={{
required: 'Please confirm your password',
validate: (value, formValues) => {
return value === formValues.password || 'Passwords do not match';
},
}}
/>
<button
type="submit"
disabled={!formState.isValid}
className="submit-button"
>
Register
</button>
</form>
);
};
Form with Dynamic Fields
📝 Dynamic Forms
Create forms with dynamic field arrays for complex data structures:
import React from 'react';
import { useForm, useFieldArray } from '@mapples/form';
const DynamicForm = () => {
const { handleSubmit, formState } = useForm({
defaultValues: {
title: '',
items: [{ name: '', quantity: 1, price: 0 }],
},
});
const { fields, append, remove } = useFieldArray('items');
const onSubmit = (data) => {
console.log('Dynamic form data:', data);
};
const addItem = () => {
append({ name: '', quantity: 1, price: 0 });
};
const removeItem = (index) => {
remove(index);
};
return (
<form onSubmit={handleSubmit(onSubmit)} className="dynamic-form">
<div className="form-group">
<label htmlFor="title">Form Title</label>
<input
{...useField('title', {
required: 'Title is required',
})}
type="text"
id="title"
placeholder="Enter form title"
/>
</div>
<div className="items-section">
<h3>Items</h3>
{fields.map((field, index) => (
<div key={field.id} className="item-row">
<div className="form-group">
<label htmlFor={`items.${index}.name`}>Item Name</label>
<input
{...useField(`items.${index}.name`, {
required: 'Item name is required',
})}
type="text"
id={`items.${index}.name`}
placeholder="Item name"
/>
</div>
<div className="form-group">
<label htmlFor={`items.${index}.quantity`}>Quantity</label>
<input
{...useField(`items.${index}.quantity`, {
required: 'Quantity is required',
min: {
value: 1,
message: 'Quantity must be at least 1',
},
})}
type="number"
id={`items.${index}.quantity`}
min="1"
/>
</div>
<div className="form-group">
<label htmlFor={`items.${index}.price`}>Price</label>
<input
{...useField(`items.${index}.price`, {
required: 'Price is required',
min: {
value: 0,
message: 'Price must be at least 0',
},
})}
type="number"
id={`items.${index}.price`}
min="0"
step="0.01"
/>
</div>
<button
type="button"
onClick={() => removeItem(index)}
className="remove-button"
>
Remove
</button>
</div>
))}
<button
type="button"
onClick={addItem}
className="add-button"
>
Add Item
</button>
</div>
<button
type="submit"
disabled={!formState.isValid}
className="submit-button"
>
Submit Form
</button>
</form>
);
};
React-Specific Features
CSS Integration
🎨 Styling
Forms works seamlessly with CSS frameworks and custom styles:
import React from 'react';
import { useForm, useField } from '@mapples/form';
import './Form.css';
const StyledForm = () => {
const { handleSubmit, formState } = useForm({
defaultValues: {
email: '',
password: '',
},
});
const emailField = useField('email', {
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Invalid email address',
},
});
const passwordField = useField('password', {
required: 'Password is required',
minLength: {
value: 8,
message: 'Password must be at least 8 characters',
},
});
const onSubmit = (data) => {
console.log('Form submitted:', data);
};
return (
<div className="form-container">
<form onSubmit={handleSubmit(onSubmit)} className="styled-form">
<div className="form-header">
<h2>Login</h2>
</div>
<div className="form-body">
<div className="form-group">
<label htmlFor="email" className="form-label">
Email Address
</label>
<input
{...emailField}
type="email"
id="email"
className={`form-input ${emailField.error ? 'error' : ''}`}
placeholder="Enter your email"
/>
{emailField.error && (
<span className="form-error">{emailField.error}</span>
)}
</div>
<div className="form-group">
<label htmlFor="password" className="form-label">
Password
</label>
<input
{...passwordField}
type="password"
id="password"
className={`form-input ${passwordField.error ? 'error' : ''}`}
placeholder="Enter your password"
/>
{passwordField.error && (
<span className="form-error">{passwordField.error}</span>
)}
</div>
</div>
<div className="form-footer">
<button
type="submit"
disabled={!formState.isValid}
className="submit-button"
>
{formState.isSubmitting ? 'Signing In...' : 'Sign In'}
</button>
</div>
</form>
</div>
);
};
Accessibility Features
♿ Accessibility
Forms provides built-in accessibility features for React web applications:
import React from 'react';
import { useForm, useField } from '@mapples/form';
const AccessibleForm = () => {
const { handleSubmit, formState } = useForm({
defaultValues: {
name: '',
email: '',
message: '',
},
});
const nameField = useField('name', {
required: 'Name is required',
});
const emailField = useField('email', {
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Invalid email address',
},
});
const messageField = useField('message', {
required: 'Message is required',
});
const onSubmit = (data) => {
console.log('Form submitted:', data);
};
return (
<form onSubmit={handleSubmit(onSubmit)} className="accessible-form">
<fieldset>
<legend>Contact Information</legend>
<div className="form-group">
<label htmlFor="name" className="form-label">
Full Name *
</label>
<input
{...nameField}
type="text"
id="name"
aria-describedby={nameField.error ? 'name-error' : undefined}
aria-invalid={nameField.error ? 'true' : 'false'}
className="form-input"
/>
{nameField.error && (
<span id="name-error" className="form-error" role="alert">
{nameField.error}
</span>
)}
</div>
<div className="form-group">
<label htmlFor="email" className="form-label">
Email Address *
</label>
<input
{...emailField}
type="email"
id="email"
aria-describedby={emailField.error ? 'email-error' : undefined}
aria-invalid={emailField.error ? 'true' : 'false'}
className="form-input"
/>
{emailField.error && (
<span id="email-error" className="form-error" role="alert">
{emailField.error}
</span>
)}
</div>
<div className="form-group">
<label htmlFor="message" className="form-label">
Message *
</label>
<textarea
{...messageField}
id="message"
rows={5}
aria-describedby={messageField.error ? 'message-error' : undefined}
aria-invalid={messageField.error ? 'true' : 'false'}
className="form-input"
/>
{messageField.error && (
<span id="message-error" className="form-error" role="alert">
{messageField.error}
</span>
)}
</div>
</fieldset>
<div className="form-actions">
<button
type="submit"
disabled={!formState.isValid}
className="submit-button"
aria-describedby="submit-help"
>
Send Message
</button>
<span id="submit-help" className="form-help">
{formState.isValid ? 'Form is ready to submit' : 'Please fill in all required fields'}
</span>
</div>
</form>
);
};
Best Practices for React
Performance Optimization
⚡ Performance
Optimize your React forms for better performance:
import React, { memo, useCallback, useMemo } from 'react';
import { useForm, useField } from '@mapples/form';
const OptimizedForm = memo(() => {
const { handleSubmit, formState } = useForm({
defaultValues: {
email: '',
password: '',
},
});
const emailField = useField('email', {
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Invalid email address',
},
});
const passwordField = useField('password', {
required: 'Password is required',
minLength: {
value: 8,
message: 'Password must be at least 8 characters',
},
});
const onSubmit = useCallback((data) => {
console.log('Form submitted:', data);
}, []);
const isFormValid = useMemo(() => formState.isValid, [formState.isValid]);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="form-group">
<label htmlFor="email">Email</label>
<input
{...emailField}
type="email"
id="email"
/>
{emailField.error && (
<span className="error">{emailField.error}</span>
)}
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input
{...passwordField}
type="password"
id="password"
/>
{passwordField.error && (
<span className="error">{passwordField.error}</span>
)}
</div>
<button type="submit" disabled={!isFormValid}>
Submit
</button>
</form>
);
});
TypeScript Integration
🔧 TypeScript
Use TypeScript for better development experience with Forms:
import React from 'react';
import { useForm, useField, FormData, FormErrors } from '@mapples/form';
interface ContactFormData {
name: string;
email: string;
message: string;
newsletter: boolean;
}
interface ContactFormErrors {
name?: string;
email?: string;
message?: string;
newsletter?: string;
}
const TypedForm = () => {
const { handleSubmit, formState } = useForm<ContactFormData, ContactFormErrors>({
defaultValues: {
name: '',
email: '',
message: '',
newsletter: false,
},
});
const nameField = useField<ContactFormData>('name', {
required: 'Name is required',
minLength: {
value: 2,
message: 'Name must be at least 2 characters',
},
});
const emailField = useField<ContactFormData>('email', {
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Invalid email address',
},
});
const messageField = useField<ContactFormData>('message', {
required: 'Message is required',
minLength: {
value: 10,
message: 'Message must be at least 10 characters',
},
});
const newsletterField = useField<ContactFormData>('newsletter');
const onSubmit = (data: ContactFormData) => {
console.log('Contact form submitted:', data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div className="form-group">
<label htmlFor="name">Name</label>
<input
{...nameField}
type="text"
id="name"
/>
{nameField.error && (
<span className="error">{nameField.error}</span>
)}
</div>
<div className="form-group">
<label htmlFor="email">Email</label>
<input
{...emailField}
type="email"
id="email"
/>
{emailField.error && (
<span className="error">{emailField.error}</span>
)}
</div>
<div className="form-group">
<label htmlFor="message">Message</label>
<textarea
{...messageField}
id="message"
rows={5}
/>
{messageField.error && (
<span className="error">{messageField.error}</span>
)}
</div>
<div className="form-group">
<label>
<input
{...newsletterField}
type="checkbox"
/>
Subscribe to newsletter
</label>
</div>
<button
type="submit"
disabled={!formState.isValid}
>
Send Message
</button>
</form>
);
};