Browse docs
Browse docs
Common errors, solutions, and debugging strategies for Dashforge applications. Find quick fixes for the most frequent issues developers encounter.
Symptom: Your field renders but doesn't register with the form. Values don't appear in onSubmit, and validation doesn't run.
❌ Problem: Field Outside Form Context
// WRONG - TextField is not inside DashForm
function MyComponent() {
return (
<div>
<TextField name="email" label="Email" />
<DashForm onSubmit={handleSubmit}>
<TextField name="password" label="Password" />
</DashForm>
</div>
);
}
// Result: "email" field won't register✅ Solution: All Fields Inside DashForm
// CORRECT - All fields inside DashForm
function MyComponent() {
return (
<DashForm onSubmit={handleSubmit}>
<TextField name="email" label="Email" />
<TextField name="password" label="Password" />
</DashForm>
);
}
// Result: Both fields register correctlySymptom: When you type in a field or select an option, the UI doesn't update or shows stale values.
❌ Problem: Controlling the Field Manually
// WRONG - Don't pass value/onChange directly
function MyForm() {
const [email, setEmail] = useState('');
return (
<DashForm onSubmit={handleSubmit}>
<TextField
name="email"
label="Email"
value={email} // ❌ Don't do this
onChange={(e) => setEmail(e.target.value)} // ❌ Don't do this
/>
</DashForm>
);
}✅ Solution: Let DashForm Manage State
// CORRECT - DashForm manages value automatically
function MyForm() {
return (
<DashForm
defaultValues={{ email: '' }}
onSubmit={handleSubmit}
>
<TextField name="email" label="Email" />
</DashForm>
);
}
// If you need to read the value, use the onSubmit callback
// or useDashForm hook, not local stateSymptom: Your reaction runs but uses outdated values. Field changes don't reflect in the reaction logic.
❌ Problem: Capturing Values Outside Reaction
// WRONG - Don't capture values from component scope
function MyForm() {
const country = watch('country'); // ❌ Stale closure
const reactions = [
{
id: 'load-states',
watch: ['country'],
run: async (ctx) => {
// Uses stale "country" from closure, not current value
const states = await fetchStates(country); // ❌ Wrong
ctx.setRuntime('state', { data: { options: states } });
}
}
];
return <DashForm reactions={reactions}>...</DashForm>;
}✅ Solution: Read Values from Context
// CORRECT - Read values from ctx inside reaction
function MyForm() {
const reactions = [
{
id: 'load-states',
watch: ['country'],
run: async (ctx) => {
// Always get fresh value from context
const country = ctx.getValue<string>('country'); // ✅ Correct
const states = await fetchStates(country);
ctx.setRuntime('state', { data: { options: states } });
}
}
];
return <DashForm reactions={reactions}>...</DashForm>;
}// ❌ Problem
function MyForm() {
const handleSubmit = (data) => {
console.log(data.email); // Error: 'data' is of type 'unknown'
};
return <DashForm onSubmit={handleSubmit}>...</DashForm>;
}✅ Solution: Define Form Values Interface
// Define your form shape
interface LoginFormValues {
email: string;
password: string;
}
function MyForm() {
const handleSubmit = (data: LoginFormValues) => {
console.log(data.email); // ✅ Type-safe
};
return (
<DashForm<LoginFormValues>
defaultValues={{ email: '', password: '' }}
onSubmit={handleSubmit}
>
<TextField name="email" label="Email" />
<TextField name="password" label="Password" />
</DashForm>
);
}// ❌ Problem
const reactions = [
{
id: 'check-country',
watch: ['country'],
run: (ctx) => {
const country = ctx.getValue('country'); // Type is 'unknown'
if (country === 'US') { // Error comparing unknown to string
// ...
}
}
}
];✅ Solution: Add Type Parameter to getValue
const reactions = [
{
id: 'check-country',
watch: ['country'],
run: (ctx) => {
const country = ctx.getValue<string>('country'); // ✅ Typed
if (country === 'US') { // ✅ Type-safe comparison
// ...
}
}
}
];Symptom: You've added validation rules but they don't run, or errors don't appear in the UI.
Common Causes
'onSubmit' + 'onTouched'✅ Correct Validation Setup
<TextField
name="email"
label="Email"
rules={{
required: 'Email is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: 'Invalid email address'
}
}}
/>
// Errors will show:
// - After user touches (blurs) the field
// - After form submission attempt
// - Errors clear when user starts typing (if field was touched)Issue: You're trying to use React Hook Form hooks (useForm, Controller) alongside Dashforge components.
❌ Don't Mix: Dashforge + Raw RHF
// WRONG - Don't use Controller with Dashforge components
import { useForm, Controller } from 'react-hook-form';
import { TextField } from '@dashforge/tw';
function MyForm() {
const { control } = useForm();
return (
<form>
<Controller
name="email"
control={control}
render={({ field }) => (
<TextField {...field} label="Email" /> // ❌ Don't do this
)}
/>
</form>
);
}✅ Use DashForm Instead
// CORRECT - Use DashForm, components register automatically
import { DashForm, TextField } from '@dashforge/tw';
function MyForm() {
return (
<DashForm onSubmit={handleSubmit}>
<TextField name="email" label="Email" />
</DashForm>
);
}
// DashForm handles all the React Hook Form setup internally
// No need for useForm, Controller, or registerWhen you encounter an issue, follow this systematic debugging approach:
DashFormProvider is an ancestor of your field. Look for the provider in the component tree.console.log(data) to see what values the form captured. Missing fields indicate registration issues.name prop and rules.ctx.getValue() instead of captured variables.If you can't find a solution here, try these resources: