Advanced Features

Framework:

This section covers Schema FormX's advanced features including custom components, form validation, group forms, and dependency linkage.

Features Overview

Custom Components

Create custom form components to meet specific design requirements.

Key Points:

  • Arbitrary UI components can be used
  • Support for registering multiple custom components
  • Special handling of empty and multiple values

Example:

import { useState } from 'react';
import { Form } from '@schema-formx/react';

const ColorPickerComponent = ({ value, onChange, colors }) => (
  <div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>
    {colors.map(color => (
      <div
        key={color}
        onClick={() => onChange?.(color)}
        style={{
          width: '24px',
          height: '24px',
          backgroundColor: color,
          borderRadius: '4px',
          cursor: 'pointer',
          border: value === color ? '2px solid #000' : '2px solid transparent'
        }}
      />
    ))}
  </div>
);

const schema = [
  {
    type: 'string',
    name: 'color',
    label: 'Color',
    component: 'ColorPicker',
    props: {
      colors: ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#ff00ff']
    }
  }
];

const InputComponent = ({ value, onChange, ...props }) => (
  <input
    value={value || ''}
    onChange={(e) => onChange?.(e.target.value)}
    style={{ width: '100%', padding: '8px', border: '1px solid #ddd', borderRadius: '4px' }}
    {...props}
  />
);

const components = { DefaultControl: InputComponent, ColorPicker: ColorPickerComponent };

<Form schema={schema} components={components} />

Learn more about custom components →

Form Validation

Schema FormX provides a built-in validation mechanism based on field configuration.

Key Points:

  • Required field validation via required property
  • Custom validation via validator function
  • Support for async validation

Example:

const schema = [
  {
    type: 'string',
    name: 'email',
    label: 'Email',
    required: true,
    validator: ({ value, label }) => {
      if (!value) return `${label} is required`;
      if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) return `${label} format is incorrect`;
      return undefined;
    }
  }
];

Learn more about form validation →

Group Forms

Group forms allow you to organize form fields into logical groups for display.

Key Points:

  • Use GroupSchema configuration
  • Support custom group containers
  • Cross-group dependency linkage

Example:

const schema = [
  {
    key: 'personal',
    label: 'Personal Information',
    fields: [
      { type: 'string', name: 'name', label: 'Name' },
      { type: 'number', name: 'age', label: 'Age' }
    ]
  },
  {
    key: 'contact',
    label: 'Contact Information',
    fields: [
      { type: 'string', name: 'phone', label: 'Phone' },
      { type: 'string', name: 'email', label: 'Email' }
    ]
  }
];

Learn more about group forms →

Dependency Linkage

Dependency linkage automatically triggers update logic when dependent field values change.

Key Points:

  • Declare dependencies with deps
  • Trigger logic with onDepsChange
  • Support async operations and data patching

Example:

const schema = [
  {
    type: 'string',
    name: 'country',
    label: 'Country',
    props: { options: ['China', 'USA', 'Japan'] }
  },
  {
    type: 'string',
    name: 'city',
    label: 'City',
    deps: ['country'],
    onDepsChange: async ({ deps, schema }) => {
      const cityMap = {
        'China': ['Beijing', 'Shanghai', 'Guangzhou'],
        'USA': ['New York', 'Los Angeles', 'Chicago'],
        'Japan': ['Tokyo', 'Osaka', 'Kyoto']
      };
      const cities = cityMap[deps[0]] || [];
      return {
        patch: { city: '' },
        schema: { ...schema, props: { options: cities } }
      };
    }
  }
];

Learn more about dependency linkage →

Feature Comparison

FeatureBasic ImplementationAdvanced Implementation
Field TypesBuilt-in typesCustom components
ValidationRequired validationCustom validators
Form LayoutSimple layoutGroup layout
Data LinkageNoneDependency linkage

Use Scenarios

Complex Business Forms

When a form contains complex business logic, dependency linkage can help:

const schema: FieldSchema[] = [
  {
    type: 'string',
    name: 'country',
    label: 'Country'
  },
  {
    type: 'string',
    name: 'city',
    label: 'City',
    deps: ['country'],
    onDepsChange: async ({ deps, schema }) => {
      const cities = await getCitiesByCountry(deps[0]);
      return {
        schema: {
          ...schema,
          props: { options: cities }
        }
      };
    }
  }
];

Dynamic Form Configuration

When form configuration needs to change based on user input:

const schema: FieldSchema[] = [
  {
    type: 'string',
    name: 'formType',
    label: 'Form Type',
    props: {
      options: ['Simple Form', 'Complex Form']
    }
  },
  {
    type: 'string',
    name: 'extraField',
    label: 'Extra Field',
    deps: ['formType'],
    onDepsChange: ({ deps, schema }) => {
      return {
        schema: {
          ...schema,
          hidden: deps[0] !== 'Complex Form'
        }
      };
    }
  }
];

Multi-Step Forms

Use group forms to implement multi-step forms:

const schema: GroupSchema[] = [
  {
    key: 'step1',
    props: { title: 'Basic Information' },
    fields: [
      { type: 'string', name: 'name', label: 'Name' },
      { type: 'string', name: 'email', label: 'Email' }
    ]
  },
  {
    key: 'step2',
    props: { title: 'Detailed Information' },
    fields: [
      { type: 'string', name: 'address', label: 'Address' },
      { type: 'string', name: 'phone', label: 'Phone' }
    ]
  }
];

Best Practices

  1. Use as needed: Choose appropriate features based on actual requirements, avoid over-engineering
  2. Performance optimization: For complex dependency linkage, pay attention to performance optimization
  3. Error handling: Add proper error handling for async operations
  4. Code reuse: Encapsulate common functionality into reusable modules