Troubleshooting
Common errors, solutions, and debugging strategies for Dashforge applications. Find quick fixes for the most frequent issues developers encounter.
Field Not Registering
Field doesn't appear in form values or validation doesn't work
Symptom: Your field renders but doesn't register with the form. Values don't appear in onSubmit, and validation doesn't run.
⚠️
Most common cause: Field is not inside a DashForm or FormProvider component
❌ 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 correctlyℹ️
Debug tip: Check React DevTools to verify DashFormProvider is an ancestor of your field component in the component tree.
Value Not Updating
Field value doesn't change when typing or selecting
Symptom: 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 state✓
Dashforge components are designed to be uncontrolled. They manage their own state through the form context. Only use defaultValues to set initial values.
Stale Closure in Reactions
Reaction uses old values instead of current form state
Symptom: 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>;
}⚠️
Always use ctx.getValue() inside reactions. Never capture values from component scope or hooks like watch(). The context always has the latest values.
TypeScript Type Errors
Common TypeScript issues and how to resolve them
Error: Type 'unknown' in onSubmit callback
// ❌ 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>
);
}Error: Type 'unknown' from getValue in reactions
// ❌ 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
// ...
}
}
}
];Validation Not Triggering
Validation rules don't run or errors don't display
Symptom: You've added validation rules but they don't run, or errors don't appear in the UI.
Common Causes
- Field not touched: Errors only show after field is touched (blur) or form submission attempt
- Wrong validation syntax: Check React Hook Form rules syntax
- Validation mode: Default mode is '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)ℹ️
Debug tip: Click on the field and then click away (blur). If validation is set up correctly, you should see the error message appear.
React Hook Form Integration
Issues when mixing Dashforge with raw React Hook Form
Issue: You're trying to use React Hook Form hooks (useForm, Controller) alongside Dashforge components.
⚠️
Dashforge components are designed to work with DashForm, not directly with React Hook Form hooks. Don't mix the two approaches.
❌ 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/ui';
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/ui';
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 registerDebugging Strategies
Tools and techniques for diagnosing Dashforge issues
When you encounter an issue, follow this systematic debugging approach:
- Check React DevTools: Verify DashFormProvider is an ancestor of your field. Look for the provider in the component tree.
- Console log in onSubmit: Add
console.log(data)to see what values the form captured. Missing fields indicate registration issues. - Check browser console: Dashforge and React Hook Form log warnings when something is misconfigured.
- Inspect field props: Use React DevTools to check if your field has the correct name prop and rules.
- Test in isolation: Create a minimal reproduction with just one field to isolate the issue.
- Check for stale closures: In reactions, always use
ctx.getValue()instead of captured variables.
✓
Pro tip: When filing a bug report, include: (1) Minimal reproduction code, (2) Expected vs actual behavior, (3) Browser console errors, (4) Dashforge version
Getting Help
Where to find additional support
If you can't find a solution here, try these resources:
- Documentation: Review the Form System, UI Components, and API Reference sections
- Examples: Check the component playgrounds and live demos
- React Hook Form Docs: For validation syntax and advanced patterns
- TypeScript Handbook: For type-related issues