You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

expo-dynamic-form

Package Overview
Dependencies
Maintainers
1
Versions
48
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

expo-dynamic-form

A highly customizable dynamic form component for React Native and Expo applications

2.2.0
latest
Source
npmnpm
Version published
Weekly downloads
29
625%
Maintainers
1
Weekly downloads
 
Created
Source

expo-dynamic-form

A highly customizable dynamic form component for React Native and Expo applications. This package provides a flexible and powerful way to create dynamic forms with various input types, validation, and multi-step support.

Features

  • 🚀 Multiple controller types:

    • Text inputs (text, email, password, number)
    • Selection inputs (select, multi-select, searchable-select)
    • Date and time inputs (date, date-of-birth, datetime)
    • Location inputs (location, multi-location, current-location)
    • Special inputs (phone, tags, currency, rich text)
    • File and image inputs (file upload, image gallery, featured image)
    • Advanced inputs (list creator, sub-form)
  • 📝 Form Capabilities:

    • Multi-step form support with dynamic navigation
    • Form validation using Zod schemas
    • Conditional field rendering
    • Dynamic field mapping
    • Nested form support
    • Integration with react-hook-form
  • 🎨 Customization Options:

    • Fully typed with TypeScript
    • Customizable UI components

Installation

# Using npm
npm install expo-dynamic-form

# Using yarn
yarn add expo-dynamic-form

Required Peer Dependencies

npm install react-hook-form @hookform/resolvers zod date-fns
npm install @react-native-community/datetimepicker @react-native-async-storage/async-storage
npm install expo-document-picker expo-file-system expo-image-picker expo-location
npm install axios

Basic Usage

Simple Form with API Submission

import React from "react";
import { View, StyleSheet } from "react-native";
import DynamicForm, { initConfig } from "expo-dynamic-form";
import { z } from "zod";

export default function App() {
  // Initialize global API configuration (optional)
  React.useEffect(() => {
    initConfig(
      {
        api: {
          baseURL: "https://your-api-base-url.com",
          headers: {
            "Content-Type": "application/json",
          },
          timeout: 30000,
        },
      },
      async () => {
        // Optional: Custom session token retrieval
        return { accessToken: "your-access-token" };
      }
    );
  }, []);

  // Create a schema for form validation
  const formSchema = z.object({
    name: z.string().min(2, "Name must be at least 2 characters"),
    email: z.string().email("Invalid email address"),
    age: z.number().min(18, "You must be at least 18 years old"),
  });

  // Define your form controllers
  const controllers = [
    {
      name: "name",
      label: "Full Name",
      type: "text",
      placeholder: "Enter your full name",
    },
    {
      name: "email",
      label: "Email Address",
      type: "email",
      placeholder: "Enter your email",
    },
    {
      name: "age",
      label: "Your Age",
      type: "number",
      placeholder: "Enter your age",
    },
  ];

  // API Submission Example
  const apiOptions = {
    api: "/users/create", // Relative API endpoint
    method: "POST",
    options: {
      // Optional axios config
      headers: {
        "X-Custom-Header": "value",
      },
    },
    extraData: {
      // Optional additional data to be sent with form submission
      source: "mobile-app",
    },
    errorHandler: (error, type) => {
      // Custom error handling
      if (type === "FORM_ERROR") {
        console.error("Form submission error:", error);
      }
    },
    onFinish: (data) => {
      // Callback after successful submission
      console.log("Submission completed:", data);
    },
  };

  return (
    <View style={styles.container}>
      <DynamicForm
        controllers={controllers}
        formSchema={formSchema}
        apiOptions={apiOptions}
        submitBtn={{ title: "Submit Form" }}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    backgroundColor: "#fff",
  },
});

Key API Submission Features

The DynamicForm component provides powerful API submission capabilities:

  • Automatic Error Handling: Handles form-level and API-level errors
  • Flexible API Configuration:
    • Specify API endpoint
    • Choose HTTP method
    • Add custom headers
    • Include extra data
  • Error Callback: Custom error handling
  • Submission Callback: Handle successful submissions
  • Global Configuration: Set base URL, default headers via initConfig()

The component uses Axios under the hood, supporting:

  • Automatic token attachment
  • Timeout configuration
  • Custom error handling
  • Flexible API interaction

Multi-step Form Example

import React from "react";
import { View, StyleSheet } from "react-native";
import DynamicForm from "expo-dynamic-form";
import { z } from "zod";

export default function App() {
  // Create schemas for each step
  const personalInfoSchema = z.object({
    name: z.string().min(2, "Name must be at least 2 characters"),
    email: z.string().email("Invalid email address"),
  });

  const addressSchema = z.object({
    street: z.string().min(5, "Please enter a valid street address"),
    city: z.string().min(2, "City is required"),
    zipCode: z.string().min(5, "ZIP code is required"),
  });

  // Define steps for your form
  const steps = [
    {
      stepName: "Personal Information",
      stepSchema: personalInfoSchema,
      controllers: [
        {
          name: "name",
          label: "Full Name",
          type: "text",
          placeholder: "Enter your full name",
        },
        {
          name: "email",
          label: "Email Address",
          type: "email",
          placeholder: "Enter your email",
        },
      ],
    },
    {
      stepName: "Address",
      stepSchema: addressSchema,
      controllers: [
        {
          name: "street",
          label: "Street Address",
          type: "text",
          placeholder: "Enter street address",
        },
        {
          name: "city",
          label: "City",
          type: "text",
          placeholder: "Enter city",
        },
        {
          name: "zipCode",
          label: "ZIP Code",
          type: "text",
          placeholder: "Enter ZIP code",
        },
      ],
    },
  ];

  // Handle form submission
  const handleSubmit = async ({ values }) => {
    console.log("Form values:", values);
    // Process form data here
  };

  return (
    <View style={styles.container}>
      <DynamicForm
        steps={steps}
        formtype="steper"
        handleSubmit={handleSubmit}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    backgroundColor: "#fff",
  },
});

Controller Types

The package supports a wide range of controller types:

  • Text Inputs

    • text: Standard text input
    • email: Email input with validation
    • password: Secure text input
    • number: Numeric input
    • textarea: Multi-line text input
  • Selection Inputs

    • select: Dropdown select
    • multi-select: Multi-selection dropdown
    • searchable-select: Searchable dropdown
    • group-checkbox: Group of checkboxes
  • Date and Time Inputs

    • date: Date picker
    • date-of-birth: Specialized date of birth picker
    • datetime: Combined date and time picker
  • Location Inputs

    • location: Single location selection
    • multi-location: Multiple location selection
    • current-location: Current device location
  • Special Inputs

    • phone: Phone number input with country code
    • tags-input: Tagging input
    • currency: Currency selection
    • rich-text: Rich text editor
  • File and Image Inputs

    • file-upload: File upload with multiple type support
    • image-gallery: Multiple image upload
    • featured-image: Single image upload
  • Advanced Inputs

    • sub-form: Nested form support
    • list-creator: Dynamic list creation
    • react-node: Custom React component input

API Reference

DynamicForm Props

PropTypeDescription
controllersFormControllerProps[]Array of form controllers for normal forms
stepsStepsType<ZodSchema>[]Array of step configurations for multi-step forms
formSchemaZodSchemaZod schema for form validation
formtype"normal" | "steper"Type of form to render (default: "normal")
handleSubmit(params: DynamicFormHanldeSubmitParamType<ZodSchema>) => Promise<void>Function to handle form submission
submitBtn{ title?: string }Configuration for submit button
stepPreview(value: any) => ReactNodeFunction to render step preview in multi-step forms
hideStepsIndicationbooleanHide step indicators in multi-step forms
apiOptionsapiOptionsTypeAPI configuration for form submission
tricker(props: any) => ReactNodeCustom trigger for form submission
propsPropsPropsTypeCustom props for form components
modalComponent(data: ModalType, setModal: (modal: ModalType) => void) => ReactNodeCustom modal component

Configuration

Global API Configuration

You can initialize global configuration for API calls using the initConfig method:

import { initConfig } from "expo-dynamic-form";
import config from "./form.config.json";
import { getSession } from "./your-session-service";

// Optional: Pass a configuration object and a session retrieval function
initConfig(config, getSession);

Configuration Object Example

Create a form.config.json in your project root:

{
  "api": {
    "baseURL": "https://your-api-base-url.com",
    "headers": {
      "Content-Type": "application/json"
    },
    "timeout": 30000
  }
}

Session Retrieval Function

The session retrieval function is optional and can be used to dynamically fetch access tokens:

// Example session service
export const getSession = async () => {
  try {
    // Retrieve stored session data
    const storedSession = await AsyncStorage.getItem("user_session");

    if (storedSession) {
      const sessionData = JSON.parse(storedSession);
      return {
        accessToken: sessionData.accessToken,
      };
    }

    return { accessToken: undefined };
  } catch (error) {
    console.error("Failed to retrieve session", error);
    return { accessToken: undefined };
  }
};

Advanced API Submission Options

apiOptions={{
  api: "/auth/login",
  method: "POST",
  options: {
    // Optional Axios configuration
    headers: {
      'X-Custom-Header': 'value'
    },
    // Additional Axios request configuration
    withCredentials: true
  },
  extraData: {
    // Additional data to be sent with the request
    deviceInfo: 'mobile-app',
    timezone: 'UTC'
  },
  onVerify: (data) => {
    // Handle verification steps (e.g., two-factor authentication)
    if (data.requiresVerification) {
      // Trigger additional verification process
      navigateToVerificationScreen();
    }
  },
  onFinish: async (data) => {
    // Handle successful submission
    await saveUserSession(data);
    navigateToMainScreen();
  }
}}

Error Handling and Form Validation

The package provides a sophisticated error handling mechanism that seamlessly integrates backend validation with Zod schema validation.

Backend Error Response Format

Your backend can return errors in two primary formats:

  • Single Error Object:
{
  "error": {
    "path": ["email"],
    "message": "Invalid Email Or Password"
  },
  "errorType": "FORM_ERROR"
}
  • Multiple Errors Array:
{
  "errors": [
    {
      "path": ["email"],
      "message": "Invalid Email address"
    },
    {
      "path": ["password"],
      "message": "Password is too short"
    }
  ],
  "errorType": "FORM_ERROR"
}
How Error Handling Works
  • Automatic Error Mapping: The form automatically maps backend errors to specific form fields
  • Supports Single and Multiple Errors: Works with both single error objects and error arrays
  • Zod Schema Compatibility: Error structure matches Zod's safeParse error format
  • Field-Specific Error Placement: Errors are displayed next to corresponding form fields

Example Backend Error Handling:

// Express.js example
app.post("/auth/login", (req, res) => {
  // Authentication logic
  if (!isValidUser) {
    return res.status(404).json({
      error: {
        path: ["email"],
        message: "Invalid Email Or Password",
      },
      errorType: "FORM_ERROR",
    });
  }

  // Multiple errors example
  if (validationFailed) {
    return res.status(400).json({
      errors: [
        {
          path: ["email"],
          message: "Email is required",
        },
        {
          path: ["password"],
          message: "Password must be at least 8 characters",
        },
      ],
      errorType: "FORM_ERROR",
    });
  }
});
Verification Flow

The package supports advanced verification scenarios, such as two-factor authentication or email verification:

{
  "succesType": "VERIFIED",
  "data": {
    "user": { ... },
    "requiresAdditionalAction": true
  }
}

Example API Options for Verification:

apiOptions={{
  api: "/auth/login",
  method: "POST",
  onVerify: (data) => {
    // Handle verification steps
    if (data.requiresVerification) {
      // Trigger additional verification process
      navigateToVerificationScreen();
    }
  },
  onFinish: async (data) => {
    // Handle final successful authentication
    if (data.succesType === "VERIFIED") {
      await saveUserSession(data.data);
      navigateToMainScreen();
    }
  }
}}
Verification Flow Characteristics
  • Flexible Verification Handling:
    • Detect when additional verification is needed
    • Support for multi-step authentication processes
  • Success Types:
    • VERIFIED: Indicates complete authentication
    • Allows for conditional navigation based on verification status
  • Rich Metadata:
    • Carry additional user or verification-related data
    • Support complex authentication scenarios

Backend Example:

app.post("/auth/login", (req, res) => {
  // Authentication logic
  if (needsTwoFactorVerification) {
    return res.status(200).json({
      succesType: "VERIFIED",
      data: {
        user: partialUserData,
        requiresVerification: true,
        verificationMethod: "otp",
      },
    });
  }

  // Complete authentication
  if (authenticationSuccessful) {
    return res.status(200).json({
      succesType: "VERIFIED",
      data: {
        user: fullUserData,
        accessToken: generatedToken,
      },
    });
  }
});

Key Configuration Features

  • Flexible Configuration:
    • Global API settings via JSON config
    • Optional session token retrieval
    • Dynamic headers and timeout
  • Seamless Token Management:
    • Automatically attach access tokens
    • Support for custom session retrieval
  • Error Handling:
    • Built-in error management
    • Custom error callback support
  • Submission Callbacks:
    • onFinish for successful submissions
    • errorHandler for custom error processing

The configuration is designed to be:

  • Optional
  • Easily customizable
  • Adaptable to different project structures

Contributing

Contributions are welcome! Please see the contributing guide for details on how to get started.

License

MIT License

Keywords

react-native

FAQs

Package last updated on 02 Jun 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts