# How Formily Handles Form Patterns: editable, readOnly, disabled, and readPretty

> Discover how Formily manages form patterns like editable, readOnly, disabled, and readPretty using the unified pattern property. Learn to control field interaction modes effectively.

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

---

**Formily uses a unified `pattern` property with four states—`editable`, `readOnly`, `disabled`, and `readPretty`—to control field interaction modes, which UI components translate into native HTML attributes or alternative renderings.**

The **alibaba/formily** repository implements a declarative pattern system that determines how form fields behave and render. Instead of manually toggling HTML attributes, developers set a field's `pattern` property, and Formily's React renderers automatically apply the correct accessibility and visual semantics.

## Understanding Formily's Pattern System

Formily models interaction states through the **`FieldPatternTypes`** enum, storing the current mode on every field instance. This approach decouples business logic from presentation, allowing patterns to cascade from forms to individual fields.

### The Four Pattern States

According to the [Field API documentation](https://github.com/alibaba/formily/blob/formily_next/packages/core/docs/api/models/Field.md#fieldpatterntypes) in [`packages/core/docs/api/models/Field.md`](https://github.com/alibaba/formily/blob/main/packages/core/docs/api/models/Field.md), Formily supports these distinct patterns:

- **`editable`** – The default state allowing full user interaction and input.
- **`readOnly`** – Displays the value but prevents modification; the field remains focusable.
- **`disabled`** – Renders the field as non-interactive and visually dimmed; maps to the native `disabled` HTML attribute.
- **`readPretty`** – Renders the value as static text without input widgets, effectively disabling interaction while preserving layout.

### Pattern Storage in Field Models

Each field instance maintains its own `pattern` attribute, defaulting to `"editable"`. The core field model exposes a **`setPattern()`** method (defined at lines 89–100 of the Field API docs) to mutate this state programmatically. When a pattern changes, Formily's reactive system triggers UI updates across all subscribed components.

## How UI Components React to Patterns

Formily's React bindings inspect the field's pattern at render time to determine which props to forward to the underlying component. This mapping happens in the core renderer and specialized wrappers.

### ReactiveField Renderer

In [`packages/react/src/components/ReactiveField.tsx`](https://github.com/alibaba/formily/blob/main/packages/react/src/components/ReactiveField.tsx) (lines 86–98), the core renderer translates pattern values into native HTML attributes:

```tsx
const disabled = !isVoidField(field)
  ? field.pattern === 'disabled' || field.pattern === 'readPretty'
  : undefined;
const readOnly = !isVoidField(field)
  ? field.pattern === 'readOnly'
  : undefined;

return React.createElement(
  getComponent(field.componentType),
  {
    disabled,
    readOnly,
    ...toJS(field.componentProps),
    value,
    onChange,
    onFocus,
    onBlur,
  },
  content,
);

```

When `pattern` is set to `disabled` or `readPretty`, the component receives `disabled={true}`, preventing focus. The `readOnly` pattern exclusively sets the `readOnly` attribute, allowing focus but blocking edits.

### Editable Wrapper for Inline Editing

The `Editable` component in [`packages/next/src/editable/index.tsx`](https://github.com/alibaba/formily/blob/main/packages/next/src/editable/index.tsx) (lines 30–45) demonstrates dynamic pattern switching between `editable` and `readPretty`:

```tsx
const useEditable = (): [boolean, (payload: boolean) => void] => {
  const pattern = useParentPattern();
  const field = useField<Field>();
  
  useLayoutEffect(() => {
    if (pattern === 'editable') {
      field.setPattern('readPretty');
    }
  }, [pattern]);

  return [
    field.pattern === 'editable',
    (payload) => {
      if (pattern !== 'editable') return;
      field.setPattern(payload ? 'editable' : 'readPretty');
    },
  ];
};

```

This hook initializes fields in `readPretty` mode and toggles them to `editable` when the user initiates inline editing, provided the parent context allows editing.

### Pattern Inheritance from Parent Forms

Fields inherit patterns from their parent form or field group via the **`useParentPattern()`** hook defined in [`packages/react/src/components/Field.tsx`](https://github.com/alibaba/formily/blob/main/packages/react/src/components/Field.tsx):

```tsx
const useParentPattern = () => {
  const field = useField<Field>();
  return field?.parent?.pattern || field?.form?.pattern;
};

```

This utility enables cascading behavior: setting `form.setPattern('disabled')` affects all descendants unless explicitly overridden by a field's local `pattern` property.

## Programmatic Pattern Control

Change interaction modes imperatively using the field or form API:

```ts
import { createForm } from '@formily/core';

const form = createForm();

// Disable specific field
form.query('username').take((field) => {
  field.setPattern('readOnly');
});

// Disable entire form
form.setPattern('disabled');

// Toggle between editable and readPretty
const toggleEdit = (field) => {
  field.setPattern(
    field.pattern === 'editable' ? 'readPretty' : 'editable'
  );
};

```

## Implementation Examples

### Mixed Pattern Form

This example demonstrates global form disability with selective field overrides using the `x-pattern` schema attribute:

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

const form = createForm({
  pattern: 'disabled', // Global default
});

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

export default () => (
  <FormProvider form={form}>
    <SchemaField>
      <SchemaField.String
        name="username"
        title="Username"
        x-pattern="editable"  // Override global disabled state
        x-decorator="FormItem"
        x-component="Input"
      />
      <SchemaField.String
        name="email"
        title="Email"
        x-pattern="readOnly"  // Native readOnly attribute
        x-decorator="FormItem"
        x-component="Input"
      />
      <SchemaField.String
        name="role"
        title="Role"
        x-pattern="readPretty"  // Rendered as static text
        x-decorator="FormItem"
        x-component="Input"
      />
    </SchemaField>
  </FormProvider>
);

```

### Click-to-Edit with Editable

Implement inline editing that switches between display and input modes:

```tsx
import { createForm } from '@formily/core';
import { FormProvider, Editable } from '@formily/next';

const form = createForm({
  pattern: 'editable',
});

export default () => (
  <FormProvider form={form}>
    <Editable.Popover title="Name">
      <span>{form.values.name || 'Click to edit'}</span>
    </Editable.Popover>
  </FormProvider>
);

```

The `Editable.Popover` component internally calls `field.setPattern('editable')` on activation and reverts to `readPretty` on blur or submission.

## Summary

- Formily stores interaction modes in the **`pattern`** property using four states: `editable`, `readOnly`, `disabled`, and `readPretty`.
- The **`ReactiveField`** renderer in [`packages/react/src/components/ReactiveField.tsx`](https://github.com/alibaba/formily/blob/main/packages/react/src/components/ReactiveField.tsx) maps these patterns to native `disabled` and `readOnly` HTML attributes.
- **`readPretty`** mode disables the field while rendering values as static text,区别于 `readOnly` which preserves focus.
- Patterns inherit from parent forms through **`useParentPattern()`**, allowing global state management with local overrides.
- Use **`field.setPattern()`** or **`form.setPattern()`** to programmatically control interaction states.

## Frequently Asked Questions

### What is the difference between readOnly and disabled in Formily?

**`readOnly`** renders the field as non-editable but keeps it focusable and included in form tab order, while **`disabled`** removes the field from focus and typically applies visual dimming. In [`packages/react/src/components/ReactiveField.tsx`](https://github.com/alibaba/formily/blob/main/packages/react/src/components/ReactiveField.tsx), `readOnly` maps to the `readOnly` HTML attribute, whereas `disabled` maps to the `disabled` attribute.

### How do I disable an entire form in Formily?

Call **`form.setPattern('disabled')`** on the form instance. This pattern cascades to all child fields via the `useParentPattern()` hook, unless individual fields explicitly override their own `pattern` property.

### Can individual fields override the form's global pattern?

Yes. Field-level patterns take precedence over inherited states. In schema definitions, use the **`x-pattern`** property (e.g., `x-pattern="editable"`) to force a specific interaction mode regardless of the parent form's setting.

### What is readPretty mode used for?

**`readPretty`** displays field values as read-only text without input widgets, often used in "click-to-edit" interfaces. According to the source in [`packages/next/src/editable/index.tsx`](https://github.com/alibaba/formily/blob/main/packages/next/src/editable/index.tsx), this pattern disables the field while presenting a cleaner visual representation of the data until the user activates edit mode.