# How to Use JSON Schema to Define Form Structures in Formily: A Complete Guide

> Learn to define form structures in Formily using JSON Schema. This guide covers standard keywords and Formily extensions for complex reactive forms. Empower your form building.

- Repository: [Alibaba/formily](https://github.com/alibaba/formily)
- Tags: how-to-guide
- Published: 2026-02-24

---

**You can define complex, reactive forms in Formily by instantiating the `Schema` class with a JSON Schema object that includes standard keywords and Formily-specific extensions like `x-component` and `x-reactions`, then rendering it via `createSchemaField`.**

Formily uses a declarative **Schema Tree** architecture that transforms standard JSON Schema definitions into fully functional form UIs. According to the alibaba/formily source code, the core `@formily/json-schema` package parses these definitions and converts them into reactive field models that power both React and Vue applications.

## The Schema Architecture

Formily's JSON Schema implementation centers on the `Schema` class located in [`packages/json-schema/src/schema.ts`](https://github.com/alibaba/formily/blob/main/packages/json-schema/src/schema.ts). This class wraps plain JSON Schema objects and provides methods for traversal, mutation, and conversion to field props.

The `Schema` constructor accepts a standard JSON Schema object and automatically builds a tree structure with parent-child relationships:

```typescript
// From packages/json-schema/src/schema.ts#L27-L38
const schema = new Schema({
  type: 'object',
  properties: {
    name: { type: 'string', title: 'Name' }
  }
})

```

Key methods include `toFieldProps()` (lines 61-66) which transforms schema nodes into `IFieldFactoryProps` consumable by Formily's field system, and `compile()` (lines 72-84) which evaluates embedded `{{expression}}` strings against a provided scope. The `ISchema` type definitions in [`packages/json-schema/src/types.ts`](https://github.com/alibaba/formily/blob/main/packages/json-schema/src/types.ts) specify the complete structure for field descriptions, including type definitions for `properties`, `items`, and extension properties.

## Defining Your First JSON Schema Form

To create a form structure, you write a JSON Schema using standard keywords plus Formily's `x-*` extension properties, instantiate the `Schema` class, and pass it to your framework-specific renderer.

### Step 1: Create the Schema Definition

Define your fields using JSON Schema syntax. Standard keywords like `type`, `title`, `default`, `enum`, and `required` work as expected, while Formily extensions control UI rendering and behavior:

```typescript
const jsonSchema = {
  type: 'object',
  properties: {
    username: {
      type: 'string',
      title: 'User Name',
      'x-component': 'Input',
      'x-decorator': 'FormItem',
      'x-validator': [
        { required: true, message: 'Required' },
        { pattern: /^[a-zA-Z0-9_]+$/, message: 'Alphanumeric only' }
      ]
    },
    age: {
      type: 'number',
      title: 'Age',
      'x-component': 'InputNumber',
      'x-decorator': 'FormItem'
    }
  }
}

```

### Step 2: Instantiate and Compile

Import the `Schema` class from your UI package and instantiate it with your definition. Call `compile()` to resolve any template expressions:

```typescript
import { Schema } from '@formily/react' // or @formily/vue

const schema = new Schema(jsonSchema)
schema.compile({ $form: form, $values: form.values })

```

### Step 3: Render with SchemaField

Use `createSchemaField` to generate a component that renders your schema tree:

```tsx
import React from 'react'
import { createForm } from '@formily/core'
import { FormProvider, createSchemaField } from '@formily/react'
import { Input, FormItem } from '@formily/antd'

const form = createForm()
const { SchemaField } = createSchemaField({
  components: { Input, FormItem }
})

export default () => (
  <FormProvider form={form}>
    <SchemaField schema={schema} />
  </FormProvider>
)

```

## Working with Formily Schema Extensions

Formily extends standard JSON Schema with `x-*` properties that define UI components, validation, and reactive behaviors. These extensions are processed by the `transformFieldProps` function (referenced in [`packages/json-schema/src/schema.ts`](https://github.com/alibaba/formily/blob/main/packages/json-schema/src/schema.ts)) to generate field configurations.

### UI Components and Decoration

- **`x-component`**: Specifies the input component (e.g., `'Input'`, `'Select'`, `'DatePicker'`)
- **`x-decorator`**: Wraps the field with layout components (e.g., `'FormItem'` for labels and error display)
- **`x-component-props`**: Passes props to the component, supporting expression values like `"{ 'style.color': '{{ $self.value === 'error' ? 'red' : '' }}' }"`

### Validation Rules

The **`x-validator`** property accepts an array of validation rules that map directly to Formily's validation engine:

```typescript
'x-validator': [
  { required: true },
  { format: 'email' },
  { validator: (value) => value.length > 5 }
]

```

### Field Reactions and Visibility

Use **`x-reactions`** for declarative field linking and **`x-visible`** for conditional rendering:

```typescript
// Simple visibility expression
'x-visible': '{{ $values.username === "admin" }}'

// Complex reactions
'x-reactions': {
  target: 'confirmPassword',
  when: '{{ $self.value }}',
  fulfill: {
    state: { visible: true }
  }
}

```

## Compiling Dynamic Expressions

The `Schema` class provides `compile()` and `shallowCompile()` static methods to evaluate template expressions within your schema. Expressions use the `{{...}}` syntax and access a scoped context containing `$form`, `$values`, `$self`, and other variables.

As implemented in [`packages/json-schema/src/schema.ts`](https://github.com/alibaba/formily/blob/main/packages/json-schema/src/schema.ts) (lines 72-84), the compilation process traverses the schema tree and evaluates expressions against the provided scope:

```typescript
// Compile with full scope
schema.compile({ 
  $form: form, 
  $values: form.values,
  $record: form.values
})

// Shallow compile for performance (single level)
Schema.shallowCompile(schema.properties, scope)

```

This enables dynamic component props, conditional validation rules, and calculated default values without imperative code.

## Advanced Schema Patterns

### Nested Objects and Arrays

Define complex nested structures using standard JSON Schema `properties` and `items` keywords. The `Schema` constructor recursively creates child nodes via `addProperty` and `setItems` methods:

```typescript
const schema = new Schema({
  type: 'object',
  properties: {
    address: {
      type: 'object',
      properties: {
        city: { type: 'string' },
        zip: { type: 'string' }
      }
    },
    contacts: {
      type: 'array',
      items: {
        type: 'object',
        properties: {
          name: { type: 'string' },
          phone: { type: 'string' }
        }
      }
    }
  }
})

```

### Schema References

Reuse schema fragments using `$ref` and `definitions`. The `findDefinitions()` method in [`packages/json-schema/src/schema.ts`](https://github.com/alibaba/formily/blob/main/packages/json-schema/src/schema.ts) resolves references locally without remote loading:

```typescript
const schema = new Schema({
  definitions: {
    address: {
      type: 'object',
      properties: {
        street: { type: 'string' }
      }
    }
  },
  type: 'object',
  properties: {
    home: { $ref: '#/definitions/address' },
    work: { $ref: '#/definitions/address' }
  }
})

```

### Version Migration with Polyfills

For upgrading from older Formily versions, use `Schema.registerPolyfills()` to transform legacy schemas:

```typescript
Schema.registerPolyfills('1.0', (schema) => {
  // Migration logic
})

```

## Summary

- **Write JSON Schema** using standard keywords and Formily extensions (`x-component`, `x-decorator`, `x-validator`, `x-reactions`) to declaratively define form structure and behavior.
- **Instantiate `new Schema(json)`** to build a traversable tree structure that maintains parent-child relationships and enables schema manipulation.
- **Call `schema.compile(scope)`** to evaluate `{{expression}}` templates against your form instance, enabling dynamic props and conditional logic.
- **Render via `createSchemaField`** by passing the compiled schema to the generated `SchemaField` component, which internally calls `toFieldProps()` to map schema nodes to field models.
- **Leverage advanced features** like `$ref` resolution for schema reuse and `x-reactions` for declarative cross-field dependencies.

## Frequently Asked Questions

### What is the difference between `x-component` and `x-decorator` in Formily JSON Schema?

**`x-component`** specifies the actual input control (such as `Input`, `Select`, or `DatePicker`) that collects user data, while **`x-decorator`** wraps that component with layout or context providers (such as `FormItem` for labels, error messages, and grid layout). Both are processed by `toFieldProps()` in [`packages/json-schema/src/schema.ts`](https://github.com/alibaba/formily/blob/main/packages/json-schema/src/schema.ts) to generate the final field configuration.

### How do I make one field visible only when another field has a specific value?

Use the **`x-visible`** extension with a template expression referencing `$values` or `$form`. For example: `'x-visible': '{{ $values.role === "admin" }}'`. Before rendering, call `schema.compile({ $values: form.values })` to evaluate the expression against the current form state.

### Can I reuse schema definitions across multiple fields?

Yes. Define reusable schemas in a **`definitions`** object at the root level, then reference them using **`$ref`** (e.g., `{ $ref: '#/definitions/address' }`). Formily's `Schema` class includes a `findDefinitions()` method that resolves these references during instantiation, merging the target schema properties into the referencing field.

### Where does Formily store the mapping between JSON Schema types and field props?

The transformation logic resides in [`packages/json-schema/src/schema.ts`](https://github.com/alibaba/formily/blob/main/packages/json-schema/src/schema.ts) within the `toFieldProps()` method (lines 61-66) and associated transformer functions. This code maps standard JSON Schema attributes (`type`, `title`, `default`) and Formily extensions (`x-component`, `x-validator`) to the `IFieldFactoryProps` interface consumed by `@formily/core`'s field creation system.