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

zod-schema-form

v1.3.0

Published

Zero-config React form generator powered by JSON Schema-flavoured definitions and Zod-friendly semantics. Point it at a schema, optionally pass theme overrides, and ship polished forms without hand-rolling inputs.

Readme

Zod Schema Form

Zero-config React form generator powered by JSON Schema-flavoured definitions and Zod-friendly semantics. Point it at a schema, optionally pass theme overrides, and ship polished forms without hand-rolling inputs.

  • Framework agnostic: Consumes plain objects—the same schema structure you would hydrate from Zod—and renders React 18+/19 components.
  • Tailwind-friendly: Ships utility-powered class names, so styles flow automatically when Tailwind scans the bundle.
  • Themable: CSS variables + theme presets provide instant visual customization with a single prop or even per-token overrides.
  • Type-safe interactions: TypeScript definitions ensure strong typing for schema, form data, handlers, and theming.

Installation & usage

Install the package alongside your React app:

npm install zod-schema-form

Import the component, your schema, and (optionally) a theme:

import ZodSchemaForm, {
  SchemaArray,
  lightTheme,
  darkTheme,
  ThemeOverrides
} from 'zod-schema-form'
import 'zod-schema-form/styles.css'

const userSchema = [
  ['name', { type: 'string', label: 'Full Name', required: true }],
  ['email', { type: 'string', label: 'Email', required: true }],
  ['age', { type: 'number', label: 'Age', minimum: 0 }],
  ['isAdmin', { type: 'boolean', label: 'Has admin access?' }]
] satisfies SchemaArray

type UserForm = {
  name: string
  email: string
  age: number
  isAdmin: boolean
}

const overrides: ThemeOverrides = {
  buttonPrimaryBackground: '#a855f7',
  focusRing: 'rgba(168, 85, 247, 0.45)'
}

export const UserFormCard = () => (
  <ZodSchemaForm<UserForm>
    schema={userSchema}
    layout='column'
    size='medium'
    onSubmit={(data) => console.log('Submit', data)}
    onValueChange={(field, value) => console.log(`${field} →`, value)}
    theme={darkTheme}
    themeOverrides={overrides}
  />
)

Styling options

  • Bundled CSS (zero-config): Import zod-schema-form/styles.css once in your app to get the default spacing, layout, and theme variable wiring—perfect for projects without Tailwind. All fallbacks are scoped to .jsf-form so they won't leak into the rest of your styles.
  • Tailwind-aware: If your project already uses Tailwind, ensure the library's files are included in the scan list so utilities resolve automatically:
export default {
  content: [
    './src/**/*.{js,jsx,ts,tsx}',
    './node_modules/zod-schema-form/dist/**/*.{js,cjs,mjs}',
    './node_modules/zod-schema-form/src/**/*.{ts,tsx}'
  ],
  theme: {
    extend: {}
  }
}

Schema definition walkthrough

Schemas are plain arrays of [fieldName, SchemaProperty]. A SchemaProperty loosely mirrors Zod field options with additional JSON Schema conveniences. Here’s the process to author a schema:

  1. Enumerate fields – use tuple entries so TypeScript can infer exact keys.
  2. Assign core metadatatype, label, description, required, etc.
  3. Add constraints – numeric bounds (minimum, maximum, exclusiveMinimum, exclusiveMaximum), string limits (minLength, maxLength), or enums (enum, enumMultiple).
  4. Shape nested data – set type: 'object' with a properties map, or type: 'array' with an items schema. Both support recursion.
  5. Handle nullable values – use nullable: true or include { type: 'null' } in anyOf if your Zod schema allows nulls.
  6. Wire defaults & sensitivitydefault, sensitive (renders password inputs), custom labels, placeholder text, and descriptions.

Primitive fields

['username', {
  type: 'string',
  label: 'Username',
  minLength: 3,
  maxLength: 24,
  description: 'Used for signing in'
}]

Numeric fields

['yearsExperience', {
  type: 'number',
  minimum: 0,
  maximum: 40,
  label: 'Years of experience'
}]

Enum selections

['role', {
  type: 'string',
  enum: ['Viewer', 'Editor', 'Owner'],
  label: 'Workspace role'
}]

Set enumMultiple: true to render checkbox chips for multi-select arrays.

Arrays

['favoriteLanguages', {
  type: 'array',
  label: 'Preferred languages',
  items: {
    type: 'string',
    enum: ['TypeScript', 'Rust', 'Go', 'Python']
  },
  minItems: 1,
  maxItems: 5
}]

Arrays can also contain structured objects. Each array item renders as its own mini-form, inheriting the same schema capabilities (nested arrays, enums, nullable fields, etc.):

['embeddings', {
  type: 'array',
  label: 'Embeddings',
  items: {
    type: 'object',
    properties: {
      vector: {
        type: 'array',
        label: 'Vector values',
        items: { type: 'number' }
      },
      text: {
        type: 'string',
        label: 'Source text',
        minLength: 2,
        maxLength: 1000
      }
    }
  }
}]

Arrays support nullable values, default lists, and numeric/string/boolean primitive types via the nested items schema.

Objects / records

['address', {
  type: 'object',
  label: 'Mailing address',
  properties: {
    street: { type: 'string', label: 'Street', required: true },
    city: { type: 'string', label: 'City', required: true },
    zipCode: { type: 'string', label: 'Postal code', required: true }
  }
}]

objectKeyType & objectValueType let you drive dictionary-style inputs when you want dynamic key/value pairs.

Nullable & anyOf

['middleName', {
  type: 'string',
  label: 'Middle name',
  nullable: true
}]

['status', {
  anyOf: [
    { type: 'string', enum: ['active', 'paused'] },
    { type: 'null' }
  ],
  label: 'Account status'
}]

Handling changes

onValueChange receives three arguments: (fieldName, nextValue, allFormData). Use it to drive live previews or derived state.


Theme system

Styling is powered by CSS variables to keep things framework-agnostic. The form computes an inline style object based on three layers:

  1. Default tokens (defaultThemeVariables) – baseline palette matching the light theme preset.
  2. theme prop – pass any object that satisfies ThemeVariables (e.g. lightTheme, darkTheme, or your custom map). These overwrite the defaults.
  3. themeOverrides prop – partial overrides applied last so you can tweak individual tokens without cloning the entire theme.

Available tokens

| Token | CSS variable | Description | | --- | --- | --- | | background | --jsf-background | Card background | | border | --jsf-border | Card border color | | shadow | --jsf-shadow | Box shadow value | | borderRadius | --jsf-border-radius | Corner radius applied to form, inputs, buttons | | fieldBorder, fieldBorderActive, fieldBackground, fieldText, fieldPlaceholder | --jsf-field-border, --jsf-field-border-active, --jsf-field-background, --jsf-field-text, --jsf-field-placeholder | Input visuals | | label, description, helper | --jsf-label, --jsf-description, --jsf-helper | Text colors for metadata | | focusRing | --jsf-focus-ring | Focus outline color | | checkboxBorder, checkboxBackground, checkboxAccent, checkboxLabel | --jsf-checkbox-border, --jsf-checkbox-background, --jsf-checkbox-accent, --jsf-checkbox-label | Checkbox cluster | | buttonPrimary*, buttonSecondary*, buttonGhost* | --jsf-button-primary-*, --jsf-button-secondary-*, --jsf-button-ghost-* | Button variants | | danger* | --jsf-danger-* | Danger/destructive actions | | chip* | --jsf-chip-* | Reserved for tag-style UI (arrays/enums) |

The exported presets include:

  • lightTheme – bright default palette (also exported as defaultThemeVariables).
  • darkTheme – deep blue-inspired aesthetic designed for night mode.
  • themes – map of { light, dark } for convenience.

Custom themes

import { ThemeVariables } from 'zod-schema-form'

const sunsetTheme: ThemeVariables = {
  ...lightTheme,
  background: '#fff7ed',
  border: '#fed7aa',
  buttonPrimaryBackground: '#f97316',
  buttonPrimaryHoverBackground: '#ea580c',
  focusRing: 'rgba(249, 115, 22, 0.35)'
}

<ZodSchemaForm schema={schema} theme={sunsetTheme} />

Demo & development

Clone the repo and run the demo playground:

npm install
npm run build # builds the library
cd demo
npm install
npm run dev

The demo showcases the same schema and theme props described above, including a live light/dark toggle.


API surface

<ZodSchemaForm />

| Prop | Type | Description | | --- | --- | --- | | schema | SchemaArray | Required field definitions | | initialValues | FormDataObject | Prefill form state | | layout | 'column' \| 'row' | Layout orientation | | size | 'small' \| 'medium' \| 'large' | Input/button sizing | | onSubmit | (data) => void | Called with typed form data | | onValueChange | (field, value, allData) => void | Field-level change handler | | isSubmitting | boolean | Disables submit button + adds aria-busy | | submitButtonText | string | Customize button label | | className | string | Extra classes appended to form container | | theme | ThemeVariables | Full theme map (defaults to lightTheme) | | themeOverrides | ThemeOverrides | Partial override for specific tokens |

Utilities

All exported from the package root:

  • sizeConfigs, rowGapBySize, columnSpacingBySize, buttonVariants, getFormClassName
  • themeVariableMap, defaultThemeVariables, lightTheme, darkTheme, themes
  • Types: SchemaArray, SchemaField, SchemaProperty, FormDataObject, ThemeVariables, ThemeOverrides, ThemeVariableKey, ZodSchemaFormProps

License

MIT © 2025 Ben Goodman