npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@taha-ui-dev/auto-form

v1.1.21

Published

AutoForm — dynamic form builder with React Hook Form, Zod and built-in shadcn-style UI

Readme

@taha-ui-dev/auto-form

Dynamic Form Builder for React & Next.js

Built with React Hook Form, Zod, and shadcn-style UI components — all bundled and ready to use.

Create complex, fully validated forms using a single schema + config object with zero boilerplate.


🚀 Features

  • ✔ Automatic form generation (schema + config-only)
  • ✔ Built on React Hook Form
  • Zod validation included
  • ✔ All common fields included (text, select, radio, date, file upload…)
  • File upload with preview, drag & drop, multi-file support
  • Multi-select (normal + popover)
  • Localized fields (e.g., en, ar)
  • Dynamic variant builder (field arrays)
  • Rich text editor with formatting options
  • Date range picker with customizable locale and timezone
  • Password field with toggle visibility
  • Shadcn-style components included
  • ✔ Optimized & fully typed for TypeScript

📥 Installation

npm install @taha-ui-dev/auto-form@latest
# or
pnpm add @taha-ui-dev/auto-form@latest
# or
yarn add @taha-ui-dev/auto-form@latest

Peer Dependencies

Make sure you have these peer dependencies installed:

npm install zod@^4.0.0
# or
pnpm add zod@^4.0.0
# or
yarn add zod@^4.0.0

🧩 Basic Usage

1. Create a Zod schema

import { z } from "zod";

export const formSchema = z.object({
  // Basic fields
  name: z.string().optional(),
  email: z.string().optional(),
  phone: z.string().optional(),
  password: z.string().optional(),
  toggle_password: z.string().optional(),

  // Date fields
  single_date: z.string().optional(),
  range_date: z
    .object({
      from: z.string().optional(),
      to: z.string().optional(),
    })
    .optional(),

  // Selection fields
  select: z.string().optional(),
  multi_select: z.array(z.string()).optional(),
  radio: z.string().optional(),
  checkbox: z.boolean().optional(),

  // Rich content
  textarea: z.string().optional(),
  rich_text: z.string().optional(),

  // File uploads
  file: z.instanceof(File).optional(),
  files: z.array(z.instanceof(File)).max(10).optional(),

  // Advanced fields
  localized_text: z
    .object({
      en: z.string(),
      ar: z.string(),
    })
    .optional(),

  // Dynamic fields array
  variants: z
    .array(
      z.object({
        variant1: z.string().optional(),
        variant2: z.string().optional(),
      })
    )
    .optional(),
});

export type FormValues = z.infer<typeof formSchema>;

2. Define your fields

import type { FieldConfig } from "@taha-ui-dev/auto-form";

export const formFields: FieldConfig[] = [
  // Basic text inputs
  {
    name: "name",
    label: "Full Name",
    field_type: "text",
    placeholder: "Enter your full name",
  },
  {
    name: "email",
    label: "Email",
    field_type: "text",
  },
  {
    name: "phone",
    label: "Phone Number",
    field_type: "phone",
  },

  // Password field
  {
    name: "password",
    label: "Password",
    field_type: "password",
  },

  // Selection fields
  {
    name: "select",
    label: "Select Option",
    field_type: "select",
    select_options: [
      { value: "option1", label: "Option 1" },
      { value: "option2", label: "Option 2" },
    ],
  },
  {
    name: "multi_select",
    label: "Multi Select",
    field_type: "multi_select",
    options_className: "border-0",
    multi_select_options: [
      { value: "option1", label: "Option 1" },
      { value: "option2", label: "Option 2" },
    ],
  },
  {
    name: "radio",
    label: "Radio Group",
    field_type: "radio",
    radio_options: [
      { value: "option1", label: "Option 1" },
      { value: "option2", label: "Option 2" },
    ],
  },
  {
    name: "checkbox",
    label: "Checkbox",
    field_type: "checkbox",
    options: {
      classes: {
        wrapper: "h-full flex items-center gap-2",
      },
    },
  },

  // Date fields
  {
    name: "single_date",
    label: "Single Date",
    field_type: "single_date",
  },
  {
    name: "range_date",
    label: "Date Range",
    field_type: "range_date",
    date_config: {
      locale: "en",
      timeZone: "Asia/Riyadh",
    },
  },

  // Rich content
  {
    name: "textarea",
    label: "Textarea",
    field_type: "textarea",
  },
  {
    name: "rich_text",
    label: "Rich Text",
    field_type: "rich_text",
    className: "col-span-2",
  },

  // File uploads
  {
    name: "file",
    label: "Single File Upload",
    field_type: "file",
    image_options: {
      accept: "image/*",
      maxSizeMb: 1,
      maxFiles: 1,
    },
  },
  {
    name: "files",
    label: "Multiple Files",
    field_type: "files",
    image_options: {
      multiple_grid: "grid-cols-2",
      accept: "image/*",
      multiple: true,
      maxSizeMb: 1,
      maxFiles: 10,
    },
  },

  // Advanced fields
  {
    name: "localized_text",
    label: "Localized Text",
    field_type: "localized_text",
  },

  // Dynamic fields array
  {
    name: "variants",
    label: "Product Variants",
    field_type: "variants",
    variants: [
      {
        name: "variant1",
        label: "Variant 1",
        field_type: "text",
      },
      {
        name: "variant2",
        label: "Variant 2",
        field_type: "text",
      },
    ],
  },
];

3. Use AutoForm

// Add this line at the top of your component if you are using Next.js
"use client";

import { AutoForm } from "@taha-ui-dev/auto-form";
import { formSchema, formFields, type FormValues } from "./form-config";

export default function ExampleForm() {
  const handleSubmit = async (values: FormValues) => {
    // Handle form submission
    console.log("Form submitted:", values);
    // Example: await api.submitForm(values);
  };

  // Set default values for controlled inputs
  const defaultValues = {
    name: "",
    email: "",
    phone: "",
    password: "",
    toggle_password: "",
    select: "",
    multi_select: [],
    checkbox: false,
    textarea: "",
    radio: "",
    single_date: "",
    range_date: { from: "", to: "" },
    variants: [],
    file: undefined,
    files: [],
    rich_text: "",
    localized_text: { en: "", ar: "" },
  };

  return (
    <div className="max-w-4xl mx-auto p-6">
      <h1 className="text-2xl font-bold mb-6">Complete Form Example</h1>
      <AutoForm
        schema={formSchema}
        fields={formFields}
        defaultValues={defaultValues}
        onSubmit={handleSubmit}
        form_id="complete-form"
        className="grid grid-cols-1 md:grid-cols-2 gap-6"
      />
    </div>
  );
}

🎨 Styling

This package uses Tailwind CSS for styling. Make sure you have Tailwind CSS set up in your project. The components follow the shadcn/ui design system.

Required CSS

Import the base styles in your application's main file:

@import "@taha-ui-dev/auto-form/style.css";

🧱 Supported Field Types

| Field Type | Component | Description | | ---------------- | --------------------- | -------------------------------------------------------------------- | | text | Text input | Standard text input field | | password | Password input | Password field with toggle visibility | | phone | Phone input | Phone number input with international country selector | | select | Dropdown/select | Single selection dropdown | | multi_select | Multi-select | Multiple selection with checkboxes or chips | | radio | Radio group | Radio button group for single selection | | checkbox | Checkbox | Single checkbox or boolean toggle | | textarea | Textarea | Multi-line text input | | rich_text | Rich text editor | WYSIWYG editor with formatting options | | single_date | Date picker | Single date selection with calendar | | range_date | Date range picker | Select a date range with start and end dates | | file | Single file upload | File upload with preview and drag & drop | | files | Multiple file upload | Multiple file upload with grid layout | | localized_text | Localized text fields | Multiple language text inputs in a single field | | variants | Dynamic field array | Repeatable group of fields for product variants or similar use cases |


📁 File Upload Fields

Single File Upload

// Schema
gallery: z.instanceof(File).optional(),

// Default value
gallery: undefined,

// Field config
{
  name: "gallery",
  label: "Upload Image",
  field_type: "file",
  image_options: {
    accept: "image/*",
    maxSizeMb: 5,
    maxFiles: 1
  }
}

Multiple Files Upload

// Schema
gallery: z.array(z.instanceof(File)).max(10).optional(),

// Default value
gallery: [],

// Field config
{
  name: "gallery",
  label: "Image Gallery",
  field_type: "files",
  image_options: {
    multiple_grid: "grid-cols-3 gap-4",  // Customize grid layout
    accept: "image/*",                   // Allowed file types
    multiple: true,                      // Allow multiple files
    maxSizeMb: 5,                        // Max file size in MB
    maxFiles: 10                         // Maximum number of files
  }
}

File Upload Features

  • Drag & Drop: Intuitive file upload interface
  • Image Previews: Thumbnails for uploaded images
  • File Type Icons: Automatic icons for different file types (PDF, DOC, ZIP, etc.)
  • Validation:
    • File type restrictions (accept prop)
    • Maximum file size (maxSizeMb)
    • Maximum number of files (maxFiles)
  • Responsive Grid: Customizable grid layout for multiple files
  • Preview & Remove: Preview and remove individual files

🌍 Localized Fields

Create multi-language text inputs with a single field. The component automatically generates language tabs and handles the nested data structure.

Basic Usage

// Schema
title: z.object({
  en: z.string(),
  ar: z.string()
}).optional(),

// Default values
{
  title: { en: "", ar: "" },
}

// Field config
{
  name: "title",
  label: "Title",
  field_type: "localized_text",
  locales: ["en", "ar"]  // Add more language codes as needed
}

Features

  • Multiple Languages: Support for any number of languages
  • Tabbed Interface: Easy switching between language inputs
  • RTL Support: Automatic text direction for RTL languages like Arabic
  • Consistent Data Structure: Outputs a clean object with language codes as keys

Example with Custom Labels

```ts
// Schema
description: z.string().optional(),

// Default value
{
  description: "",
}

// Field config
{
  name: "description",
  label: "Description",
  field_type: "rich_text",
  className: "min-h-[200px]"  // Set minimum height
}

Features

  • Rich Text Formatting: Bold, italic, headings, lists, quotes, and more
  • Media Support: Embed images and videos
  • Code Blocks: Syntax highlighting for code snippets
  • Tables: Create and edit tables
  • Mentions & Hashtags: Coming soon
  • Word Count: Track content length
  • Auto-save: Draft saving functionality

Advanced Configuration

{
  name: "content",
  label: "Article Content",
  field_type: "rich_text",
  className: "min-h-[400px] border rounded-lg p-4",
  editorOptions: {
    placeholder: "Start writing your article here...",
    extensions: [
      // Add custom extensions
    ],
    onUpdate: (editor) => {
      // Handle editor updates
      console.log(editor.getHTML());
    }
  },
  // Character/word limit
  maxLength: 5000,
  showWordCount: true
}

Validation Example

// Schema with validation
description: z
  .string()
  .min(50, "Description must be at least 50 characters")
  .max(5000, "Description cannot exceed 5000 characters"),
  // Conditional validation based on another field
  z.object({
    hasDescription: z.boolean(),
    description: z.string().superRefine((val, ctx) => {
      if (ctx.parent.hasDescription && !val) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: "Description is required when hasDescription is true",
        });
      }
    }),
  });

Custom Styling

/* Customize the rich text editor appearance */
.rich-text-editor {
  @apply border rounded-lg overflow-hidden;

  /* Toolbar */
  .ProseMirror-toolbar {
    @apply bg-gray-50 border-b p-2 flex flex-wrap gap-1;
  }

  /* Content area */
  .ProseMirror {
    @apply p-4 min-h-[200px] focus:outline-none;
  }

  /* Active button state */
  button.is-active {
    @apply bg-gray-200;
  }
}

Extending Functionality

You can extend the rich text editor with additional Tiptap extensions:

import { Extension } from "@tiptap/core";
import { ReactRenderer } from "@tiptap/react";

export const CustomExtension = Extension.create({
  name: "customExtension",
  // Extension configuration
});

// Then use it in your field config
{
  field_type: "rich_text",
  extensions: [CustomExtension],
  // ...other options
}

✔ AutoForm Props

interface AutoFormProps<T extends z.ZodObject<any>> {
  schema: T;
  mode?: "onSubmit" | "onChange" | "onBlur" | "all" | "onTouched";
  is_dev?: boolean;
  fields: FieldConfig<T>[];
  defaultValues?: DefaultValues<z.infer<T>>;
  onSubmit: (values: z.infer<T>) => Promise<void> | void;
  className?: string;
  form_id?: string;
  buttons?: {
    className?: string;
    submit?: {
      text?: string;
      className?: string;
    };
    reset?: {
      text?: string;
      className?: string;
    };
  };
}

🎨 Styling

This package ships with lightweight shadcn-style components, including:

  • Button
  • Input
  • Select
  • Popover
  • Radio
  • Checkbox
  • Calendar
  • Separator
  • Textarea
  • ScrollArea
  • Spinner
  • Input Group

You do not need to install shadcn/ui.


📦 Bundle Output

This library generates:

| Format | File | | ------ | ----------------------- | | ES | dist/auto-form.es.js | | CJS | dist/auto-form.cjs.js | | Types | dist/index.d.ts |


🤝 Contributing

PRs and feedback are welcome.


📝 License

MIT © Taha