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

react-smart-fields

v2.4.0

Published

A flexible and highly customizable dynamic form builder for React with validation, conditional fields, theming, and headless rendering.

Readme

React Smart Fields

npm downloads license

react-smart-fields is a powerful dynamic form renderer for React with:

  • configurable field schemas
  • built-in + custom validation
  • conditional visibility/disable/required rules
  • async options for selects
  • nested field names (user.addresses[0].city)
  • theme presets + headless mode + full render slots

Installation

npm install react-smart-fields

or

yarn add react-smart-fields

Quick Start

// 1. Import the default styles once (e.g. in your root layout or App.tsx)
import 'react-smart-fields/styles.css';

import { DynamicFields, FieldConfig } from "react-smart-fields";

const fields: FieldConfig[] = [
  { name: "name", label: "Name", type: "text", required: true },
  {
    name: "email",
    label: "Email",
    type: "email",
    required: true,
    pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
    patternMessage: "Please enter a valid email",
  },
  {
    name: "country",
    label: "Country",
    type: "select",
    placeholder: "Select country",
    options: [
      { label: "India", value: "in" },
      { label: "United States", value: "us" },
    ],
  },
  {
    name: "newsletter",
    label: "Subscribe to newsletter",
    type: "checkbox",
    defaultValue: true,
  },
];

export default function App() {
  return (
    <DynamicFields
      fields={fields}
      title="Profile"
      description="Update your profile details"
      theme="default"
      size="md"
      onChange={(values, meta) => {
        console.log(values, meta?.errors);
      }}
    />
  );
}

Major Capabilities

  • Validation engine: required, min/max, minLength/maxLength, pattern, and validate
  • Conditional behavior: showWhen, disableWhen, requiredWhen
  • Nested paths: dot/bracket field names are supported
  • Async select options: loadOptions with loadOptionsOn: "mount" | "change"
  • Theme presets: default, minimal, filled, underline
  • Headless mode: set headless to fully control UI
  • Render slots: renderField, renderControl, renderLabel, renderDescription, renderError
  • State styling hooks: stateClassNames for invalid, disabled, readonly, dirty, touched

Component Props

| Prop | Type | Required | Description | | --- | --- | --- | --- | | fields | FieldConfig[] | ✅ | Field schema array | | onChange | (values, meta?) => void | ✅ | Fires on every value/meta update | | value | Record<string, any> | ❌ | Controlled mode values | | defaultValues | Record<string, any> | ❌ | Initial values (uncontrolled mode) | | resolver | (values) => errors \| Promise<errors> | ❌ | External validation resolver | | validateMode | "change" \| "blur" | ❌ | Validation trigger mode | | showErrorWhen | "always" \| "touched" \| "dirty" | ❌ | Error visibility strategy | | headless | boolean | ❌ | Disables built-in styling | | theme | "default" \| "minimal" \| "filled" \| "underline" | ❌ | Built-in visual preset | | size | "sm" \| "md" \| "lg" | ❌ | Input/label sizing | | ui | UiClassMap | ❌ | Global slot class overrides | | stateClassNames | StateClassNames | ❌ | State class hooks | | renderField | (ctx) => ReactNode | ❌ | Full custom field renderer | | renderControl | (ctx) => ReactNode | ❌ | Custom control renderer | | renderLabel | (ctx) => ReactNode | ❌ | Custom label renderer | | renderDescription | (ctx) => ReactNode | ❌ | Custom helper text renderer | | renderError | (ctx) => ReactNode | ❌ | Custom error renderer | | title | string | ❌ | Form heading | | description | string | ❌ | Form subtitle |

Legacy class props are still supported for backward compatibility: className, inputClassName, labelClassName, mainFieldClassName, fieldClassName, errorClassName, selectClassName, optionClassName, checkboxClassName, radioClassName.

FieldConfig API

type FieldConfig = {
  name: string;
  label?: string;
  type:
    | "text"
    | "number"
    | "select"
    | "radio"
    | "checkbox"
    | "textarea"
    | "email"
    | "password"
    | "tel"
    | "url"
    | "date";

  // values/options
  defaultValue?: any;
  placeholder?: string;
  options?: { label: string; value: string | number | boolean | null | undefined; disabled?: boolean }[];
  loadOptions?: (ctx: { values: Record<string, any>; field: FieldConfig }) => Promise<FieldOption[]>;
  loadOptionsOn?: "mount" | "change";

  // behavior
  disabled?: boolean;
  readOnly?: boolean;
  showWhen?: (values: Record<string, any>) => boolean;
  disableWhen?: (values: Record<string, any>) => boolean;
  required?: boolean;
  requiredWhen?: (values: Record<string, any>) => boolean;
  requiredMessage?: string;

  // validation
  min?: number;
  max?: number;
  minLength?: number;
  maxLength?: number;
  pattern?: RegExp;
  patternMessage?: string;
  validate?: (value: any, values: Record<string, any>) => string | undefined | null;

  // value transforms
  transformIn?: (storedValue: any, values: Record<string, any>) => any;
  transformOut?: (rawValue: any, values: Record<string, any>) => any;

  // styling/rendering
  className?: string;
  inputClassName?: string;
  labelClassName?: string;
  errorClassName?: string;
  ui?: UiClassMap;
  renderControl?: (ctx: RenderControlContext) => ReactNode;
};

Customization Examples

1) Conditional + Nested Fields

const fields: FieldConfig[] = [
  { name: "accountType", label: "Account Type", type: "select", options: [
    { label: "Individual", value: "individual" },
    { label: "Business", value: "business" },
  ]},
  {
    name: "company.name",
    label: "Company Name",
    type: "text",
    showWhen: (values) => values.accountType === "business",
    requiredWhen: (values) => values.accountType === "business",
  },
  {
    name: "addresses[0].city",
    label: "Primary City",
    type: "text",
    required: true,
  },
];

2) Async Select Options

{
  name: "state",
  label: "State",
  type: "select",
  loadOptionsOn: "change",
  loadOptions: async ({ values }) => {
    if (!values.country) return [];
    const response = await fetch(`/api/states?country=${values.country}`);
    const data = await response.json();
    return data.map((item: any) => ({ label: item.name, value: item.code }));
  },
}

3) Headless + Slots

<DynamicFields
  fields={fields}
  headless
  renderField={({ field, labelNode, controlNode, errorNode, helpNode }) => (
    <div key={field.name} className="mb-6">
      {labelNode}
      <div className="mt-2">{controlNode}</div>
      <div className="mt-1">{helpNode}</div>
      <div className="mt-1">{errorNode}</div>
    </div>
  )}
  onChange={(values) => console.log(values)}
/>

4) Resolver Validation

<DynamicFields
  fields={fields}
  resolver={(values) => {
    const errors: Record<string, string> = {};
    if (values.password !== values.confirmPassword) {
      errors.confirmPassword = "Passwords do not match";
    }
    return errors;
  }}
  onChange={(values, meta) => {
    console.log(meta?.errors);
  }}
/>

Type Exports

import type {
  FieldConfig,
  FieldOption,
  FieldType,
  DynamicFieldsProps,
  UiClassMap,
  StateClassNames,
  ChangeMeta,
  RenderControlContext,
  RenderFieldContext,
} from "react-smart-fields";

Author

Name: Pratik Panchal
GitHub: @Pratikpanchal25

License

MIT — Free to use, modify and distribute.

Contributing

Pull requests are welcome! If you find bugs, feel free to open an issue.