CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-refinedev--core

React meta-framework for building enterprise CRUD applications with authentication, data management, and headless UI integration

Pending
Overview
Eval results
Files

forms.mddocs/

Forms & Data Input

Advanced form management with auto-save, validation, mutation handling, and integration with popular form libraries.

Capabilities

Core Form Management

useForm Hook

Orchestrates data hooks for create, edit, and clone operations with advanced features like auto-save, validation, and automatic redirects.

/**
 * Orchestrates form operations with data management, validation, and auto-save
 * @param params - Form configuration options
 * @returns Form state, handlers, and mutation controls
 */
function useForm<TQueryFnData = BaseRecord, TError = HttpError, TVariables = {}, TData = TQueryFnData, TResponse = BaseRecord, TResponseError = HttpError>(
  params?: UseFormConfig<TQueryFnData, TError, TVariables, TData, TResponse, TResponseError>
): UseFormReturnType<TQueryFnData, TError, TVariables, TData, TResponse, TResponseError>;

interface UseFormConfig<TQueryFnData, TError, TVariables, TData, TResponse, TResponseError> {
  /** Form action type - determines behavior */
  action?: "create" | "edit" | "clone";
  /** Resource name - inferred from route if not provided */
  resource?: string;
  /** Record ID for edit/clone operations */
  id?: BaseKey;
  /** Where to redirect after successful submission */
  redirect?: RedirectAction;
  /** Additional metadata for operations */
  meta?: MetaQuery;
  /** Mutation mode for optimistic updates */
  mutationMode?: MutationMode;
  /** Callback on successful mutation */
  onMutationSuccess?: (data: TResponse, variables: TVariables, context: any, isAutoSave: boolean) => void;
  /** Callback on mutation error */
  onMutationError?: (error: TResponseError, variables: TVariables, context: any, isAutoSave: boolean) => void;
  /** Auto-save configuration */
  autoSave?: {
    /** Enable auto-save functionality */
    enabled?: boolean;
    /** Debounce delay in milliseconds */
    debounce?: number;
    /** Invalidate queries when component unmounts */
    invalidateOnUnmount?: boolean;
  };
  /** Success notification configuration */
  successNotification?: SuccessErrorNotification | false;
  /** Error notification configuration */
  errorNotification?: SuccessErrorNotification | false;
  /** Data provider name to use */
  dataProviderName?: string;
  /** Query options for data fetching */
  queryOptions?: UseQueryOptions<TQueryFnData, TError>;
  /** Mutation options for create/update */
  createMutationOptions?: UseMutationOptions<TResponse, TResponseError, UseCreateParams<TVariables>>;
  /** Mutation options for update operations */
  updateMutationOptions?: UseMutationOptions<TResponse, TResponseError, UseUpdateParams<TVariables>>;
  /** Timeout for undoable mutations */
  undoableTimeout?: number;
  /** Cache invalidation configuration */
  invalidates?: Array<string>;
}

interface UseFormReturnType<TQueryFnData, TError, TVariables, TData, TResponse, TResponseError> {
  /** Form submission handler */
  onFinish: (values: TVariables) => Promise<void>;
  /** Auto-save handler for form changes */
  onFinishAutoSave: (values: TVariables) => Promise<void>;
  /** Whether form operations are loading */
  formLoading: boolean;
  /** Mutation result for create/update operations */
  mutation: UseMutationResult<TResponse, TResponseError, UseCreateParams<TVariables> | UseUpdateParams<TVariables>>;
  /** Query result for fetching existing data (edit/clone) */
  query: UseQueryResult<TQueryFnData, TError>;
  /** Auto-save props for form libraries */
  autoSaveProps: AutoSaveProps;
  /** Current record ID */
  id?: BaseKey;
  /** Function to set record ID */
  setId: React.Dispatch<React.SetStateAction<BaseKey | undefined>>;
  /** Redirect configuration */
  redirect: RedirectAction;
  /** Loading overtime information */
  overtime: UseLoadingOvertimeReturnType;
}

interface AutoSaveProps {
  /** Current auto-save status */
  status: "loading" | "success" | "error" | "idle";
  /** Error from auto-save operation */
  error?: TResponseError;
  /** Data from successful auto-save */
  data?: TResponse;
}

Usage Example:

import { useForm } from "@refinedev/core";
import { useEffect } from "react";

interface PostFormData {
  title: string;
  content: string;
  status: "draft" | "published";
  categoryId: number;
}

function PostForm() {
  const {
    onFinish,
    onFinishAutoSave,
    formLoading,
    query,
    autoSaveProps,
    id,
    setId
  } = useForm<PostFormData>({
    action: "edit", // or "create", "clone"
    resource: "posts",
    redirect: "list",
    autoSave: {
      enabled: true,
      debounce: 2000 // Auto-save after 2 seconds of inactivity
    },
    onMutationSuccess: (data, variables, context, isAutoSave) => {
      if (isAutoSave) {
        console.log("Auto-saved successfully");
      } else {
        console.log("Form submitted successfully");
      }
    }
  });
  
  const [formData, setFormData] = useState<PostFormData>({
    title: "",
    content: "",
    status: "draft",
    categoryId: 1
  });
  
  // Load existing data for edit mode
  useEffect(() => {
    if (query.data) {
      setFormData(query.data.data);
    }
  }, [query.data]);
  
  // Auto-save on form changes
  useEffect(() => {
    const timeoutId = setTimeout(() => {
      onFinishAutoSave(formData);
    }, 2000);
    
    return () => clearTimeout(timeoutId);
  }, [formData, onFinishAutoSave]);
  
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    await onFinish(formData);
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>Title:</label>
        <input
          value={formData.title}
          onChange={(e) => setFormData(prev => ({ ...prev, title: e.target.value }))}
          disabled={formLoading}
        />
      </div>
      
      <div>
        <label>Content:</label>
        <textarea
          value={formData.content}
          onChange={(e) => setFormData(prev => ({ ...prev, content: e.target.value }))}
          disabled={formLoading}
        />
      </div>
      
      <div>
        <label>Status:</label>
        <select
          value={formData.status}
          onChange={(e) => setFormData(prev => ({ ...prev, status: e.target.value as "draft" | "published" }))}
          disabled={formLoading}
        >
          <option value="draft">Draft</option>
          <option value="published">Published</option>
        </select>
      </div>
      
      {/* Auto-save indicator */}
      <div className="auto-save-status">
        {autoSaveProps.status === "loading" && <span>Saving...</span>}
        {autoSaveProps.status === "success" && <span>Saved ✓</span>}
        {autoSaveProps.status === "error" && <span>Save failed ✗</span>}
      </div>
      
      <button type="submit" disabled={formLoading}>
        {formLoading ? "Submitting..." : "Submit"}
      </button>
    </form>
  );
}

Form Library Integrations

React Hook Form Integration

Integration patterns with React Hook Form for advanced form validation and state management.

/**
 * Integration with React Hook Form
 * @param params - Configuration for React Hook Form integration
 * @returns Combined form state and Refine form handlers
 */
function useFormWithReactHookForm<TFormData, TQueryFnData = BaseRecord, TError = HttpError, TResponse = BaseRecord>(
  params?: UseFormConfig<TQueryFnData, TError, TFormData, TQueryFnData, TResponse, TError>
): UseFormWithReactHookFormReturnType<TFormData, TQueryFnData, TError, TResponse>;

interface UseFormWithReactHookFormReturnType<TFormData, TQueryFnData, TError, TResponse> extends UseFormReturnType<TQueryFnData, TError, TFormData, TQueryFnData, TResponse, TError> {
  /** Register form fields with React Hook Form */
  register: UseFormRegister<TFormData>;
  /** Handle form submission with validation */
  handleSubmit: UseFormHandleSubmit<TFormData>;
  /** Form state and errors */
  formState: FormState<TFormData>;
  /** Set form values programmatically */
  setValue: UseFormSetValue<TFormData>;
  /** Get form values */
  getValues: UseFormGetValues<TFormData>;
  /** Watch form field changes */
  watch: UseFormWatch<TFormData>;
}

React Hook Form Example:

import { useForm as useRefineForm } from "@refinedev/core";
import { useForm as useReactHookForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";

const schema = yup.object({
  title: yup.string().required("Title is required"),
  content: yup.string().min(10, "Content must be at least 10 characters"),
  email: yup.string().email("Invalid email format")
});

function PostFormWithValidation() {
  const { onFinish, formLoading, query } = useRefineForm();
  
  const {
    register,
    handleSubmit,
    formState: { errors },
    setValue,
    watch
  } = useReactHookForm({
    resolver: yupResolver(schema),
    defaultValues: query.data?.data
  });
  
  const onSubmit = (data: any) => {
    onFinish(data);
  };
  
  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <input {...register("title")} placeholder="Title" />
        {errors.title && <span>{errors.title.message}</span>}
      </div>
      
      <div>
        <textarea {...register("content")} placeholder="Content" />
        {errors.content && <span>{errors.content.message}</span>}
      </div>
      
      <button type="submit" disabled={formLoading}>
        Submit
      </button>
    </form>
  );
}

Formik Integration

Integration patterns with Formik for form state management and validation.

/**
 * Integration with Formik
 * @param params - Configuration for Formik integration
 * @returns Formik props combined with Refine form handlers
 */
function useFormWithFormik<TFormData>(
  params?: UseFormConfig & FormikConfig<TFormData>
): UseFormWithFormikReturnType<TFormData>;

interface UseFormWithFormikReturnType<TFormData> {
  /** Formik form props */
  formikProps: FormikProps<TFormData>;
  /** Refine form handlers */
  refineProps: UseFormReturnType;
}

Auto-Save & Draft Management

AutoSaveIndicator Component

Visual indicator for auto-save status with customizable appearance.

/**
 * Visual indicator for auto-save status
 * @param props - Auto-save indicator configuration
 * @returns Auto-save status indicator component
 */
function AutoSaveIndicator(props?: AutoSaveIndicatorProps): JSX.Element;

interface AutoSaveIndicatorProps {
  /** Auto-save status */
  status: "loading" | "success" | "error" | "idle";
  /** Custom messages for each status */
  messages?: {
    loading?: string;
    success?: string;
    error?: string;
    idle?: string;
  };
  /** Custom styling */
  style?: React.CSSProperties;
  /** Custom class names */
  className?: string;
}

Usage Example:

import { AutoSaveIndicator, useForm } from "@refinedev/core";

function FormWithAutoSave() {
  const { autoSaveProps, onFinishAutoSave } = useForm({
    autoSave: { enabled: true, debounce: 1000 }
  });
  
  return (
    <div>
      <form>
        {/* Form fields */}
      </form>
      
      <AutoSaveIndicator
        status={autoSaveProps.status}
        messages={{
          loading: "Saving draft...",
          success: "Draft saved",
          error: "Failed to save draft"
        }}
      />
    </div>
  );
}

Form Validation

Client-Side Validation

Integration with validation libraries for client-side form validation.

/**
 * Validation configuration for forms
 */
interface ValidationConfig<TFormData> {
  /** Validation schema */
  schema?: ValidationSchema<TFormData>;
  /** Custom validation functions */
  rules?: ValidationRules<TFormData>;
  /** Validation mode */
  mode?: "onChange" | "onBlur" | "onSubmit";
  /** Re-validation mode */
  reValidateMode?: "onChange" | "onBlur" | "onSubmit";
}

interface ValidationSchema<TFormData> {
  [K in keyof TFormData]?: ValidationRule[];
}

interface ValidationRule {
  /** Validation type */
  type: "required" | "email" | "min" | "max" | "pattern" | "custom";
  /** Validation value */
  value?: any;
  /** Error message */
  message: string;
}

interface ValidationRules<TFormData> {
  [K in keyof TFormData]?: (value: TFormData[K], formData: TFormData) => string | undefined;
}

Form State Management

Form Loading States

Managing different loading states during form operations.

/**
 * Form loading state management
 */
interface FormLoadingState {
  /** Whether form is submitting */
  submitting: boolean;
  /** Whether data is being fetched */
  fetching: boolean;
  /** Whether auto-save is in progress */
  autoSaving: boolean;
  /** Whether form is validating */
  validating: boolean;
}

Form Error Handling

Comprehensive error handling for form operations.

/**
 * Form error handling configuration
 */
interface FormErrorHandling<TError> {
  /** Field-specific errors */
  fieldErrors?: Record<string, string[]>;
  /** General form errors */
  formErrors?: string[];
  /** Server validation errors */
  serverErrors?: TError;
  /** Error display mode */
  errorMode?: "field" | "summary" | "both";
}

Advanced Form Features

Multi-Step Forms

Support for multi-step form workflows with data persistence.

/**
 * Multi-step form management
 */
interface MultiStepFormConfig {
  /** Current step index */
  currentStep: number;
  /** Total number of steps */
  totalSteps: number;
  /** Step validation configuration */
  stepValidation?: Record<number, ValidationConfig>;
  /** Data persistence between steps */
  persistData?: boolean;
}

interface MultiStepFormActions {
  /** Go to next step */
  nextStep: () => void;
  /** Go to previous step */
  previousStep: () => void;
  /** Go to specific step */
  goToStep: (step: number) => void;
  /** Complete the form */
  complete: () => void;
}

Dynamic Forms

Support for forms with dynamic field generation and conditional logic.

/**
 * Dynamic form field configuration
 */
interface DynamicFieldConfig {
  /** Field type */
  type: "text" | "number" | "select" | "checkbox" | "radio" | "textarea" | "date";
  /** Field name/key */
  name: string;
  /** Display label */
  label: string;
  /** Default value */
  defaultValue?: any;
  /** Field options for select/radio */
  options?: Array<{ label: string; value: any }>;
  /** Validation rules */
  validation?: ValidationRule[];
  /** Conditional display logic */
  condition?: (formData: any) => boolean;
  /** Field-specific props */
  props?: Record<string, any>;
}

Types

type RedirectAction = "list" | "edit" | "show" | "create" | "clone" | false;

interface UseLoadingOvertimeReturnType {
  /** Elapsed time since loading started */
  elapsedTime?: number;
}

interface FormSubmissionResult<TData> {
  /** Whether submission was successful */
  success: boolean;
  /** Response data */
  data?: TData;
  /** Error information */
  error?: any;
  /** Redirect configuration */
  redirect?: {
    to: string;
    type?: "push" | "replace";
  };
}

interface FormFieldProps {
  /** Field name */
  name: string;
  /** Field value */
  value: any;
  /** Change handler */
  onChange: (value: any) => void;
  /** Blur handler */
  onBlur?: () => void;
  /** Field error */
  error?: string;
  /** Whether field is disabled */
  disabled?: boolean;
  /** Whether field is required */
  required?: boolean;
}

Install with Tessl CLI

npx tessl i tessl/npm-refinedev--core

docs

application-setup.md

authentication.md

data-operations.md

forms.md

index.md

navigation.md

tables-lists.md

utilities.md

tile.json