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

antd-meta-form

v0.1.0

Published

Meta driven Ant Design form helper for React with AntD v5/v6 support.

Downloads

185

Readme

Antd meta Form

CI npm version license: MIT

Meta-driven Ant Design form helper for React, with AntD v5 and v6 support.

Inspired by eBay/nice-form-react, implemented fresh and focused on Ant Design only. It fixes the two long-standing gaps of the reference project:

  • condition/render work with dependencies — they are evaluated inside the AntD Form.Item dependency lifecycle, so only the dependent field area re-renders (nice-form-react#8).
  • Multiple fields per form-list itemlistItemMeta accepts a single field, an array of fields, or a function returning either (nice-form-react#14).

Why

Forms are repetitive. Describe them as metadata — possibly loaded from an API — and render real AntD forms with validation, layout, conditional visibility, and dynamic lists, without giving up access to any underlying Form.Item prop.

Installation

pnpm add antd-meta-form
# or: npm install / yarn add

Peer dependencies

| Package | Range | Notes | | --- | --- | --- | | antd | >=5 <7 | v5 and v6 supported | | react | >=18 | | | react-dom | >=18 | | | @ant-design/icons | >=5 <7 | optional |

The package ships ESM + CJS + TypeScript declarations and never bundles React or AntD. No AntD CSS is imported — your app keeps full control over styling and theming.

Example apps

Runnable Vite playgrounds for both supported AntD majors live in examples/: examples/vite-antd5 (antd 5 + React 18) and examples/vite-antd6 (antd 6 + React 19).

cd examples/vite-antd6
pnpm install
pnpm dev

Basic example

import { AntdMetaForm, type MetaFormMeta } from 'antd-meta-form';
import { Button, Form } from 'antd';

const meta: MetaFormMeta = {
  columns: 2,
  layout: 'vertical',
  fields: [
    {
      key: 'favoriteFruit',
      label: 'Favorite Fruit',
      widget: 'select',
      required: true,
      options: ['Apple', 'Orange', 'Other'],
    },
    {
      key: 'otherFruit',
      label: 'Other Fruit',
      widget: 'input',
      dependencies: ['favoriteFruit'],
      condition: ({ form }) => form.getFieldValue('favoriteFruit') === 'Other',
    },
    {
      key: 'submit',
      render: () => (
        <Button type="primary" htmlType="submit">
          Submit
        </Button>
      ),
    },
  ],
};

export default function Page() {
  const [form] = Form.useForm();
  return <AntdMetaForm form={form} meta={meta} onFinish={(values) => console.log(values)} />;
}

Rendering inside an existing AntD Form

import { Form } from 'antd';
import { MetaFormItems } from 'antd-meta-form';

function MyForm() {
  const [form] = Form.useForm();
  return (
    <Form form={form} layout="vertical" onFinish={console.log}>
      <MetaFormItems form={form} meta={meta} />
    </Form>
  );
}

Dynamic visibility with dependencies

condition, visibleWhen, and render are executed inside a no-style Form.Item that carries the field's dependencies (or shouldUpdate). When a dependency changes, only that field area re-renders — exactly how AntD intends dependencies to work.

{
  key: 'otherFruit',
  label: 'Other Fruit',
  widget: 'input',
  dependencies: ['favoriteFruit'],
  condition: ({ form }) => form.getFieldValue('favoriteFruit') === 'Other',
}

Do not combine dependencies and shouldUpdate on the same field — AntD warns that they conflict. If both are present, this package logs a development warning and uses dependencies.

Note: like AntD itself, dependency re-evaluation is triggered by field updates flowing through the form store (user input, Form.Item controls). It is not a watcher on arbitrary external state.

JSON-safe conditions with visibleWhen

Metadata that comes from an API cannot carry functions. Use visibleWhen instead of condition:

{
  key: 'otherFruit',
  label: 'Other Fruit',
  widget: 'input',
  dependencies: ['favoriteFruit'],
  visibleWhen: { field: 'favoriteFruit', op: 'eq', value: 'Other' },
}

Operators: eq, neq, in, notIn, exists, empty, gt, gte, lt, lte. Pass an array of expressions to combine them with AND.

Multi-field form-list

{
  key: 'addresses',
  label: 'Addresses',
  widget: 'form-list',
  listItemMeta: [
    { key: 'street', label: 'Street', widget: 'input', required: true },
    { key: 'city', label: 'City', widget: 'select', options: ['Beijing', 'Shanghai'] },
  ],
}

Values map to addresses[0].street, addresses[0].city, …

The classic single-field form (nice-form-react compatible) still works — the field binds to the list item value itself:

{
  key: 'addresses',
  label: 'Addresses',
  widget: 'form-list',
  listItemMeta: { widget: 'select', options: ['Beijing', 'Shanghai', 'Nanjing'] },
}

listItemMeta can also be a function (ctx) => FieldMeta | FieldMeta[] receiving { listField, index, operation, errors, parentField, form, meta }.

List options: minItems, maxItems, allowMove, addItemButtonLabel, addItemButtonProps, removeItemButtonLabel, listItemLayout (columns/columnGap/rowGap/layout for the row grid).

Nested form-list

List item fields can themselves be form-list fields:

{
  key: 'contacts',
  label: 'Contacts',
  widget: 'form-list',
  listItemMeta: [
    { key: 'name', label: 'Name', widget: 'input' },
    { key: 'phones', label: 'Phones', widget: 'form-list', listItemMeta: { widget: 'input' } },
  ],
}

Custom widgets

import { defineWidget } from 'antd-meta-form';

const ColorSwatch = ({ value, onChange }) => /* value/onChange injected by Form.Item */ null;

defineWidget('color-swatch', ColorSwatch);

// optional convertField hook, e.g. for checked-style widgets:
defineWidget('my-switch', MySwitch, (field) => ({ ...field, valuePropName: 'checked' }));

A field's widget can also be a component directly: { key: 'x', widget: MyWidget }.

createWidgetRegistry() is exported for building isolated registries.

View mode

Set viewMode: true on the whole meta or on a single field to render read-only values. Customize with renderView(value, ctx) or viewWidget/viewWidgetProps. Option values are mapped back to their labels automatically.

API reference

<AntdMetaForm form? meta {...formProps} />

Creates (or reuses) an AntD form and renders the metadata. All other props are forwarded to AntD Form.

<MetaFormItems form meta pathPrefix? />

Renders metadata fields inside an existing AntD Form.

MetaFormMeta

| Prop | Type | Description | | --- | --- | --- | | fields | FieldMeta[] | Field definitions | | columns | number | Grid columns (default 1) | | columnGap / rowGap | number \| string | Grid gaps | | layout | 'horizontal' \| 'vertical' \| 'inline' | AntD form layout | | labelWidth | number \| string | Fixed label column width | | initialValues | object | Initial form values | | viewMode | boolean | Render all fields read-only | | disabled | boolean | Disable all widgets |

FieldMeta

Extends AntD FormItemProps (so rules, tooltip, extra, validateTrigger, valuePropName, getValueFromEvent, normalize, preserve, hidden, … all pass through), plus:

| Prop | Type | Description | | --- | --- | --- | | key | string | Required. Becomes name; dots create nested paths (user.name['user','name']; prefix !!! for a literal key) | | name | NamePath | Explicit AntD name path override | | widget | string \| Component \| null | Widget name or component (default 'input') | | widgetProps | object | Props for the widget | | options | (string \| number \| object)[] | For select / radio-group / checkbox-group; scalars are auto-converted | | required | boolean | Adds a required rule if none exists | | condition | (ctx) => boolean | Function visibility (use with dependencies) | | visibleWhen | expression or array | JSON-safe visibility (use with dependencies) | | render | (ctx) => ReactNode | Replace the whole field rendering | | renderView / viewWidget | | View-mode rendering | | fullWidth / colSpan / rowSpan | | Grid placement | | listItemMeta + list props | | See form-list above |

Built-in widgets

Every AntD data-entry component is registered:

input, text, search, password, textarea, input-otp, number, select, auto-complete, cascader, tree-select, mentions, radio-group, checkbox, checkbox-group, switch, segmented, slider, rate, color-picker, date-picker, range-picker, time-picker, time-range-picker, transfer, upload, form-list, view-text.

Widget-specific notes:

  • upload — automatically wired with valuePropName: 'fileList' and a getValueFromEvent that unwraps the upload event. Provide the trigger via children (e.g. a button) and Upload props via widgetProps.
  • transfer — automatically wired with valuePropName: 'targetKeys'; pass dataSource/render via widgetProps.
  • tree-selectoptions are mapped onto treeData (labels/values/children align with treeData's default field names); a widgetProps.treeData takes precedence.
  • color-picker requires antd ≥ 5.5 and input-otp requires antd ≥ 5.16; on older 5.x versions these names are simply not registered.

AntD v5/v6 compatibility

  • Only stable public AntD APIs are used: Form, Form.Item, Form.List, Form.ErrorList, plus the standard input widgets.
  • CI runs the test matrix against AntD 5 + React 18 and AntD 6 + React 18/19.
  • AntD is a peer dependency and never bundled, so your app's AntD version (and theme) wins.

Contributing & releasing

Development setup, the CI matrix, and the release/publishing process are documented in CONTRIBUTING.md.

License

MIT