This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
# Install dependencies
npm install
# Build all packages (parallel)
npm run build
# Build all packages (sequential, use if parallel causes issues)
npm run build-serial
# Run all tests
npm test
# Lint
npm run lint
# Prettier check / format
npm run cs-check
npm run cs-format
# Run a single package's tests
cd packages/core && npm test
# Watch mode for a single package
cd packages/core && npm run test:watch
# Update snapshots
cd packages/snapshot-tests && npm run test:update
# Start the playground (interactive demo)
cd packages/playground && npm start
# Full sanity check (lint + build + test)
npm run sanity-checkIndividual package builds output three module formats: build:cjs, build:esm, build:umd.
This is an npm workspaces + Nx monorepo. All packages live under packages/ and are scoped as @rjsf/*.
| Package | Role |
|---|---|
@rjsf/utils |
Shared types, 80+ utility functions, schema helpers. No UI dependencies. |
@rjsf/core |
Core Form component, Bootstrap 3 as default theme, withTheme() HOC. |
@rjsf/validator-ajv8 |
AJV 8-based validator. Exported via customizeValidator(). |
@rjsf/snapshot-tests |
Shared snapshot test suite consumed by all theme packages. |
Theme packages (@rjsf/mui, @rjsf/antd, @rjsf/chakra-ui, etc.) |
UI-library-specific implementations of fields, widgets, and templates. |
@rjsf/playground |
Vite app importing all themes, used for manual testing and demos. |
@rjsf/docs |
Docusaurus documentation site. |
The Registry object is the core extension point passed to every field/widget/template:
Registry = {
fields, // Map of field type → Field component
widgets, // Map of widget name → Widget component
templates, // Layout/structural templates
rootSchema, // Root JSON Schema
formContext, // Arbitrary context object threaded to all components
schemaUtils, // Schema parsing & validation helpers
translateString,
globalFormOptions,
}Override fields/widgets/templates per-form via props, or globally via withTheme().
Every theme package follows the same structure:
- Imports
withThemefrom@rjsf/core - Defines custom
Templates,Widgets, and optionallyFields - Calls
withTheme({ templates, widgets, fields })to produce a themedForm - Exports:
Form(default),Theme,Templates,Widgets
- Fields handle schema-level logic (ObjectField, ArrayField, MultiSchemaField for oneOf/anyOf, etc.)
- Widgets handle individual input rendering (TextWidget, SelectWidget, CheckboxWidget, etc.)
- Templates control structural/layout rendering (FieldTemplate, ArrayFieldTemplate, ButtonTemplates, etc.)
Fields select which widget to render based on schema type and ui:widget. Templates wrap the output for consistent styling.
- Caller provides
schema,validator(required),formData, anduiSchema FormcreatesschemaUtilsfrom validator + schema- Schema is recursively decomposed into fields → widgets → templates
- On change/blur: callbacks fire with updated
formDataanderrorSchema - On submit: full validation runs, then
onSubmitfires (oronErrorif invalid)
- Schema helpers:
findSchemaDefinition,mergeSchemas,getSchemaType,createSchemaUtils - Form data:
mergeDefaultsWithFormData,removeOptionalEmptyObjects - Error handling:
toErrorSchema,toErrorList - Enum helpers:
enumOptionsSelectValue,enumOptionsDeselectValue - React hooks:
useDeepCompareMemo,useFileWidgetProps,useAltDateWidgetProps
- TypeScript strict mode, ES2020 target
- Prettier: single quotes, JSX single quotes, 120-char print width
- ESLint: enforces semicolons, curly braces, no-console, React Hooks rules
- Pre-commit hook (Husky + lint-staged) auto-formats and lints staged files
- Vitest, jsdom, Testing Library
- Snapshot tests in
@rjsf/snapshot-testsare shared across theme packages — runtest:updatethere when changing core rendering - Node >=20 required