Usage | Dashforge-UI
DocsStarter Kits
v0.1.0-alpha

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 →

On This Page