react-jsonschema-form Agent Skills & AI Rules

GitHub

A React component for building Web forms from JSON Schema.

15,922 stars TypeScript TypeScript 1 file ยท ~125,743 tokens #data-validation#forms#json#json-schema#react#ui#web
RAW Rules
122 Discovered Rules โ€ข ~248,398 Estimated Tokens
Quick:
Loading skill content...

Claude Agent Guidelines & System Prompt

CLAUDE.md claude-rule ~1,730 tokens
Raw
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Commands

```bash
# Install dependencies
pnpm install

# Build all packages (parallel)
pnpm run build

# Build all packages (sequential, use if parallel causes issues)
pnpm run build-serial

# Run all tests
pnpm test

# Lint (oxlint, type-aware)
pnpm run lint

# Typecheck every package and its tests
pnpm run typecheck

# Dead code / unused dependency check
pnpm run knip

# Format check / format source files (oxfmt)
pnpm run cs-check
pnpm run cs-format

# Format check / format every file in the repo, including configs and markdown
pnpm run format-check
pnpm run format

# Run a single package's tests
cd packages/core && pnpm test

# Watch mode for a single package
cd packages/core && pnpm run test:watch

# Update snapshots
cd packages/snapshot-tests && pnpm run test:update

# Start the playground (interactive demo)
cd packages/playground && pnpm start

# Full sanity check (lint + knip + build + test)
pnpm run sanity-check
```

CI runs lint, knip, build, typecheck, and test in that order, so run those before pushing. Per-package `tsc` misses the test and playground projects; only the root `typecheck` covers them.

Individual package builds run `build:ts` (`tsc -b`, emits `lib/`) and then bundle `dist/` in three formats: `build:cjs` and `build:esm` via esbuild, `build:umd` via rollup.

## Architecture

This is an **pnpm workspaces + Nx** monorepo. All packages live under `packages/` and are scoped as `@rjsf/*`.

### Package roles

| 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.                                           |

### Registry pattern (the plugin system)

The `Registry` object is the core extension point passed to every field/widget/template:

```typescript
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, // Form-level options available to every template, field, and widget
  globalUiOptions, // Optional; global ui:options applied to every field
  uiSchemaDefinitions, // Optional; uiSchema fragments keyed by $ref path, applied when that $ref resolves
};
```

Override fields/widgets/templates per-form via props, or globally via `withTheme()`.

### Theme pattern

Every theme package follows the same structure:

1. Imports `withTheme` from `@rjsf/core`
2. Defines custom `Templates`, `Widgets`, and optionally `Fields`
3. Calls `withTheme({ templates, widgets, fields })` to produce a themed `Form`
4. Exports: `Form` (default), `Theme`, `Templates`, `Widgets`

### Field โ†’ Widget โ†’ Template hierarchy

- **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.

When making a change to a widget or template, consider if the change should be generalized to all theme packages. If substantial logic is duplicated across themes, consider refactoring the logic to `@rjsf/utils` or `@rjsf/core`.

### Form rendering flow

1. Caller provides `schema`, `validator` (required), `formData`, and `uiSchema`
2. `Form` creates `schemaUtils` from validator + schema
3. Schema is recursively decomposed into fields โ†’ widgets โ†’ templates
4. On change/blur: callbacks fire with updated `formData` and `errorSchema`
5. On submit: full validation runs, then `onSubmit` fires (or `onError` if invalid)

### Key `@rjsf/utils` exports to know

- Schema helpers: `findSchemaDefinition`, `mergeSchemas`, `getSchemaType`, `createSchemaUtils`
- Form data: `mergeDefaultsWithFormData`, `removeOptionalEmptyObjects`
- Error handling: `toErrorSchema`, `toErrorList`
- Enum helpers: `enumOptionsSelectValue`, `enumOptionsDeselectValue`
- React hooks: `useDeepCompareMemo`, `useFileWidgetProps`, `useAltDateWidgetProps`

## Code style

- **TypeScript strict mode**, `esnext` target, `verbatimModuleSyntax` (type-only imports must be `import type`), relative imports include the `.ts`/`.tsx` extension
- **oxfmt** (`.oxfmtrc.json`): single quotes, JSX single quotes, 120-char print width, sorted imports with React first
- **oxlint** (`.oxlintrc.json`): the `airbnb-typescript` rule set translated to oxlint, plus `typescript`, `react`, `jsx-a11y`, and `import` plugins; enforces curly braces, no-console, React rules of hooks
- **knip** (`knip.jsonc`): fails CI on unused files, exports, and dependencies
- Pre-commit hook (Husky + lint-staged) runs `oxlint --fix` and `oxfmt` on staged files

## Code comments

- Default to no comments. Write self-documenting code โ€” clear names and structure โ€” as the primary means of explanation.
- When a comment is warranted, explain the WHY (rationale, constraints, non-obvious tradeoffs), not the WHAT โ€” well-named code already says what it does.
- Don't leave "before/after" or diff-style commentary in code comments or in this file. That belongs in commit messages and PR descriptions, not in code that has to keep reading true after the change ships.

## Changelog

- When adding an entry to `CHANGELOG.md`, append it as the last bullet under the relevant package's heading (e.g. `## @rjsf/daisyui`) โ€” after the existing bullets, not inserted above or among them.

## Testing

- Vitest, jsdom, Testing Library; shared config in `testing/vitest.base.mts`, extended per package
- Tests resolve `@rjsf/*` imports to TypeScript source via the `@rjsf/source` export condition, so no build is needed before running them
- `@rjsf/utils` and the validator packages enforce 100% coverage
- Snapshot tests in `@rjsf/snapshot-tests` are shared across theme packages โ€” run `test:update` there when changing core rendering
- Node >=20 required; `.nvmrc` pins 24