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 🙏

© 2026 – Pkg Stats / Ryan Hefner

json-form-craft

v1.0.2

Published

A lightweight, extensible, schema-driven React form builder that generates fully functional forms from JSON.

Downloads

441

Readme

json-form-craft

npm version license bundle size

A lightweight, extensible, schema-driven React form builder that generates fully functional, accessible forms from JSON schemas powered by React Hook Form.


Features

  • Zero Runtime Overhead: Built on top of react-hook-form with zero extra UI framework dependencies.
  • 📦 Tree-shakeable & Dual Bundle: Ships ESM and CommonJS declarations generated automatically.
  • 🎨 Fully Customisable & Accessible: Includes clean default styles, ARIA attributes, keyboard navigation, and full custom className control.
  • 🧩 Extensible: Seamlessly register custom field components (e.g. Rich Text, Rating Stars, Custom Sliders).
  • 🛠️ 18+ Built-in Field Types: Supports text, email, password, number, textarea, select, radio, checkbox, switch, date, time, datetime, file, hidden, color, range, url, tel.
  • 📘 TypeScript Native: Complete type definitions exported for all schemas, props, and hooks.

Installation

npm install json-form-craft react-hook-form
# or
yarn add json-form-craft react-hook-form
# or
pnpm add json-form-craft react-hook-form

Note: react and react-dom (>=18.0.0) are peer dependencies.


Quick Start

Import FormBuilder and pass your JSON schema:

import { FormBuilder, FieldSchema } from "json-form-craft";
import "json-form-craft/styles.css"; // Optional clean default styling

const schema: FieldSchema[] = [
  {
    type: "text",
    name: "name",
    label: "Name",
    placeholder: "Enter your name",
    required: true,
  },
  {
    type: "email",
    name: "email",
    label: "Email",
    placeholder: "Enter your email",
  },
  {
    type: "select",
    name: "country",
    label: "Country",
    options: [
      { label: "India", value: "india" },
      { label: "USA", value: "usa" },
    ],
  },
];

function App() {
  return (
    <FormBuilder
      schema={schema}
      onSubmit={(values) => console.log("Submitted values:", values)}
    />
  );
}

export default App;

Supported Field Types

| Field Type | Rendered Element | Notes | | :--- | :--- | :--- | | text | <input type="text"> | Standard single-line text input | | email | <input type="email"> | Includes built-in email regex validation | | password | <input type="password"> | Secure password field | | number | <input type="number"> | Converts value to number automatically | | textarea | <textarea> | Supports rows and cols schema props | | select | <select> | Supports options array and multiple mode | | radio | <input type="radio"> | Radio group based on options | | checkbox | <input type="checkbox"> | Single boolean checkbox or checkbox array group | | switch | <input type="checkbox" role="switch"> | Styled toggle switch | | date | <input type="date"> | Date picker with min and max constraints | | time | <input type="time"> | Time picker | | datetime | <input type="datetime-local"> | Datetime picker | | file | <input type="file"> | Supports accept and multiple | | hidden | <input type="hidden"> | Hidden form field | | color | <input type="color"> | Color picker | | range | <input type="range"> | Slider range input | | url | <input type="url"> | Includes built-in URL format validation | | tel | <input type="tel"> | Telephone input |


Validation Examples

Validation rules can be defined using shorthand attributes (like required: true) or fine-grained validation objects (validation: { minLength: { value: 8, message: "Min 8 chars" } }).

[
  {
    "type": "text",
    "name": "username",
    "label": "Username",
    "required": "Username is mandatory",
    "validation": {
      "minLength": {
        "value": 3,
        "message": "Username must be at least 3 characters"
      },
      "maxLength": 20
    }
  },
  {
    "type": "number",
    "name": "age",
    "label": "Age",
    "validation": {
      "min": { "value": 18, "message": "Must be 18+" },
      "max": 99
    }
  },
  {
    "type": "text",
    "name": "confirmPassword",
    "label": "Confirm Password",
    "validation": {
      "custom": "(val, allValues) => val === allValues.password || 'Passwords do not match'"
    }
  }
]

Custom Synchronous / Asynchronous Validators in JS/TS:

const schema: FieldSchema[] = [
  {
    type: "text",
    name: "username",
    label: "Username",
    validation: {
      custom: async (value) => {
        const isAvailable = await checkUsernameAvailable(value);
        return isAvailable || "Username is already taken";
      },
    },
  },
];

Custom Field Components (Extensibility)

You can register custom components for any custom type string using the customFields prop:

import { FormBuilder, CustomFieldProps } from "json-form-craft";

// 1. Define your custom component
const RatingField: React.FC<CustomFieldProps> = ({ field, value, onChange }) => {
  return (
    <div>
      <label>{field.label}</label>
      <button type="button" onClick={() => onChange?.(5)}>
        Selected: {value || 0} ⭐
      </button>
    </div>
  );
};

// 2. Use in schema
const schema = [
  {
    type: "rating", // Custom type
    name: "score",
    label: "Customer Score",
  },
];

// 3. Register customFields
<FormBuilder
  schema={schema}
  customFields={{ rating: RatingField }}
  onSubmit={(values) => console.log(values)}
/>;

API Documentation

FormBuilder Component Props

interface FormBuilderProps {
  /** Array of field schema definitions */
  schema: FieldSchema[];
  /** Default initial form values */
  defaultValues?: Record<string, any>;
  /** Callback on valid form submission */
  onSubmit: (values: Record<string, any>) => void | Promise<void>;
  /** Callback fired whenever any form value changes */
  onChange?: (values: Record<string, any>) => void;
  /** Callback fired when validation fails on submit */
  onError?: (errors: Record<string, any>) => void;
  /** Disable all form fields */
  disabled?: boolean;
  /** Form element CSS class */
  className?: string;
  /** Submit button customization */
  submitButton?:
    | React.ReactNode
    | {
        text?: string;
        className?: string;
        disabled?: boolean;
        hidden?: boolean;
      };
  /** Custom field components mapping */
  customFields?: Record<string, CustomFieldComponent>;
  /** Extra children inside form */
  children?: React.ReactNode;
}

Headless Hook: useFormBuilder

For full control over form layout, use useFormBuilder:

import { useFormBuilder } from "json-form-craft";

function CustomLayoutForm() {
  const { form, handleSubmit, renderFields } = useFormBuilder({
    schema: mySchema,
    onChange: (values) => console.log("Live values:", values),
  });

  return (
    <form onSubmit={handleSubmit((data) => console.log(data))}>
      <div className="grid grid-cols-2">
        {renderFields()}
      </div>
      <button type="submit">Submit</button>
    </form>
  );
}

TypeScript Usage

All types are exported directly from json-form-craft:

import type {
  FieldSchema,
  FieldType,
  BuiltInFieldType,
  FieldOption,
  FieldValidationRules,
  FormBuilderProps,
  CustomFieldProps,
} from "json-form-craft";

Styling Guide

json-form-craft ships with optional clean CSS (json-form-craft/styles.css). You can customize the look via CSS variables or by passing custom class names per field:

CSS Variables Customization

:root {
  --jfk-primary: #6366f1;
  --jfk-primary-hover: #4f46e5;
  --jfk-border: #e2e8f0;
  --jfk-radius: 0.5rem;
}

ClassName Schema Overrides

{
  "type": "text",
  "name": "company",
  "label": "Company Name",
  "containerClassName": "my-field-container",
  "labelClassName": "my-label-style",
  "inputClassName": "my-input-style",
  "errorClassName": "my-error-style"
}

Publishing & Build Instructions

Build Library

npm run build

Compiles TypeScript and outputs distribution bundles in dist/:

  • dist/index.js (ES Module)
  • dist/index.cjs (CommonJS)
  • dist/index.d.ts (TypeScript Declaration)
  • dist/style.css (CSS Bundle)

Run Unit Tests

npm run test

Publish to NPM

npm publish --access public

Repository

GitHub Repository


License

MIT © json-form-craft