
Security News
TC39 Advances 11 Proposals for Math Precision, Binary APIs, and More
TC39 advances 11 JavaScript proposals, with two moving to Stage 4, bringing better math, binary APIs, and more features one step closer to the ECMAScript spec.
expo-dynamic-form
Advanced tools
A highly customizable dynamic form component for React Native and Expo applications
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.
🚀 Multiple controller types:
📝 Form Capabilities:
🎨 Customization Options:
# Using npm
npm install expo-dynamic-form
# Using yarn
yarn add expo-dynamic-form
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
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",
},
});
The DynamicForm
component provides powerful API submission capabilities:
initConfig()
The component uses Axios under the hood, supporting:
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",
},
});
The package supports a wide range of controller types:
Text Inputs
text
: Standard text inputemail
: Email input with validationpassword
: Secure text inputnumber
: Numeric inputtextarea
: Multi-line text inputSelection Inputs
select
: Dropdown selectmulti-select
: Multi-selection dropdownsearchable-select
: Searchable dropdowngroup-checkbox
: Group of checkboxesDate and Time Inputs
date
: Date pickerdate-of-birth
: Specialized date of birth pickerdatetime
: Combined date and time pickerLocation Inputs
location
: Single location selectionmulti-location
: Multiple location selectioncurrent-location
: Current device locationSpecial Inputs
phone
: Phone number input with country codetags-input
: Tagging inputcurrency
: Currency selectionrich-text
: Rich text editorFile and Image Inputs
file-upload
: File upload with multiple type supportimage-gallery
: Multiple image uploadfeatured-image
: Single image uploadAdvanced Inputs
sub-form
: Nested form supportlist-creator
: Dynamic list creationreact-node
: Custom React component inputProp | Type | Description |
---|---|---|
controllers | FormControllerProps[] | Array of form controllers for normal forms |
steps | StepsType<ZodSchema>[] | Array of step configurations for multi-step forms |
formSchema | ZodSchema | Zod 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) => ReactNode | Function to render step preview in multi-step forms |
hideStepsIndication | boolean | Hide step indicators in multi-step forms |
apiOptions | apiOptionsType | API configuration for form submission |
tricker | (props: any) => ReactNode | Custom trigger for form submission |
props | PropsPropsType | Custom props for form components |
modalComponent | (data: ModalType, setModal: (modal: ModalType) => void) => ReactNode | Custom modal component |
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);
Create a form.config.json
in your project root:
{
"api": {
"baseURL": "https://your-api-base-url.com",
"headers": {
"Content-Type": "application/json"
},
"timeout": 30000
}
}
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 };
}
};
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();
}
}}
The package provides a sophisticated error handling mechanism that seamlessly integrates backend validation with Zod schema validation.
Your backend can return errors in two primary formats:
{
"error": {
"path": ["email"],
"message": "Invalid Email Or Password"
},
"errorType": "FORM_ERROR"
}
{
"errors": [
{
"path": ["email"],
"message": "Invalid Email address"
},
{
"path": ["password"],
"message": "Password is too short"
}
],
"errorType": "FORM_ERROR"
}
safeParse
error formatExample 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",
});
}
});
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();
}
}
}}
VERIFIED
: Indicates complete authenticationBackend 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,
},
});
}
});
onFinish
for successful submissionserrorHandler
for custom error processingThe configuration is designed to be:
Contributions are welcome! Please see the contributing guide for details on how to get started.
MIT License
FAQs
A highly customizable dynamic form component for React Native and Expo applications
The npm package expo-dynamic-form receives a total of 29 weekly downloads. As such, expo-dynamic-form popularity was classified as not popular.
We found that expo-dynamic-form demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
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.
Security News
TC39 advances 11 JavaScript proposals, with two moving to Stage 4, bringing better math, binary APIs, and more features one step closer to the ECMAScript spec.
Research
/Security News
A flawed sandbox in @nestjs/devtools-integration lets attackers run code on your machine via CSRF, leading to full Remote Code Execution (RCE).
Product
Customize license detection with Socket’s new license overlays: gain control, reduce noise, and handle edge cases with precision.