Usage
Build your first form. Add validation. Make fields conditional. Handle submission. Each step builds on the last.
1. Add the required providers
Quick one-time setup
import { DashThemeProvider } from '@dashforge/theme-core';
import { MuiThemeAdapter } from '@dashforge/theme-mui';
function App() {
return (
<DashThemeProvider mode="light">
<MuiThemeAdapter>
{/* Your app content */}
</MuiThemeAdapter>
</DashThemeProvider>
);
}2. Your first form
Fields register themselves. Validation runs automatically. Errors display on touch.
import { DashForm } from '@dashforge/forms';
import { TextField, Button } from '@dashforge/ui';
function LoginForm() {
const handleSubmit = (data) => {
console.log('Submitted:', data);
// { email: '[email protected]', password: '...' }
};
return (
<DashForm
defaultValues={{ email: '', password: '' }}
onSubmit={handleSubmit}
>
<TextField
name="email"
label="Email"
type="email"
rules={{
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Invalid email',
},
}}
/>
<TextField
name="password"
label="Password"
type="password"
rules={{
required: 'Password is required',
minLength: {
value: 8,
message: 'At least 8 characters',
},
}}
/>
<Button type="submit" variant="contained">
Sign In
</Button>
</DashForm>
);
}No Controller. No manual error wiring. No watch() for touched state.
3. Make fields conditional
No watch() or conditional JSX. Fields react to form state automatically.
import { DashForm } from '@dashforge/forms';
import { TextField, Select, Checkbox, Button } from '@dashforge/ui';
function ShippingForm() {
return (
<DashForm defaultValues={{
country: '',
state: '',
hasCompany: false,
companyName: '',
}}>
<Select
name="country"
label="Country"
options={[
{ value: 'us', label: 'United States' },
{ value: 'ca', label: 'Canada' },
]}
rules={{ required: 'Select a country' }}
/>
{/* State field: only visible for US */}
<TextField
name="state"
label="State"
visibleWhen={(form) =>
form.getNode('country')?.value === 'us'
}
rules={{ required: 'State required' }}
/>
<Checkbox
name="hasCompany"
label="Shipping to a company?"
/>
{/* Company name: only visible when checkbox is true */}
<TextField
name="companyName"
label="Company Name"
visibleWhen={(form) =>
form.getNode('hasCompany')?.value === true
}
rules={{ required: 'Company name required' }}
/>
<Button type="submit" variant="contained">
Continue
</Button>
</DashForm>
);
}The dependency lives on the field. No scattered watch() calls in the parent.
4. Write custom validation
Same validation API as React Hook Form. Access form values without manual wiring.
<TextField
name="password"
label="Password"
type="password"
rules={{
required: 'Password required',
validate: {
hasUpperCase: (value) =>
/[A-Z]/.test(value) || 'Need uppercase letter',
hasNumber: (value) =>
/[0-9]/.test(value) || 'Need a number',
hasSpecial: (value) =>
/[!@#$%^&*]/.test(value) || 'Need special character',
},
}}
/>
<TextField
name="confirmPassword"
label="Confirm Password"
type="password"
rules={{
required: 'Confirm password',
validate: (value, formValues) =>
value === formValues.password || 'Passwords must match',
}}
/>5. Submit to your API
Handle async submission with loading states and error handling
import { useState } from 'react';
import { DashForm } from '@dashforge/forms';
import { TextField, Button } from '@dashforge/ui';
function RegistrationForm() {
const [isSubmitting, setIsSubmitting] = useState(false);
const [error, setError] = useState(null);
const handleSubmit = async (data) => {
setIsSubmitting(true);
setError(null);
try {
const response = await fetch('/api/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
if (response.ok) {
// Redirect or show success
} else {
setError('Registration failed');
}
} catch (err) {
setError('Network error');
} finally {
setIsSubmitting(false);
}
};
return (
<DashForm
defaultValues={{ name: '', email: '' }}
onSubmit={handleSubmit}
>
<TextField
name="name"
label="Name"
rules={{ required: 'Name required' }}
/>
<TextField
name="email"
label="Email"
type="email"
rules={{ required: 'Email required' }}
/>
{error && <div style={{ color: 'red' }}>{error}</div>}
<Button
type="submit"
variant="contained"
disabled={isSubmitting}
>
{isSubmitting ? 'Submitting...' : 'Register'}
</Button>
</DashForm>
);
}You know the patterns
Now explore the full component library: TextField, Select, NumberField, DateTimePicker, Checkbox, RadioGroup, and more.
Component Library →