How to Build Forms Visually with Formily's Form Builder: A Complete Guide

Formily's Form Builder, built on the Designable visual editor framework, lets you create complex forms through drag-and-drop by initializing a Designable engine and registering Formily components as draggable resources.

The alibaba/formily repository provides a powerful Form Builder that eliminates manual JSON schema writing. Built atop the open-source Designable framework, this visual editor integrates deeply with Formily's core to offer a canvas-based form design experience. This guide explains how to assemble the builder using the actual source implementation and official documentation.

Architecture of the Visual Form Builder

The Form Builder consists of four integrated layers. According to the source code in packages/core/src/types.ts, Formily exposes a designable?: boolean property in IFormProps that enables Designable hooks when set to true. The architecture flows through Designable's core engine, Formily-specific component bridges, a React-based UI kit, and the actual Formily field components used as drag targets.

The typical workflow involves:

  • Designable Core – Provides the engine (createDesigner), workspace management, undo/redo history, and plugin system.
  • Formily Integration – Bridges Designable primitives with Formily's Form, Field, and UI components while maintaining the designable metadata flag.
  • UI Kit – Offers React widgets like Designer, Workspace, ResourceWidget, and SettingsPanel to compose the interface.
  • Form Components – Exposes draggable entities including Input, Select, ArrayCards, and FormLayout from packages like @designable/formily-antd.

Installation Prerequisites

Before implementing the builder, install the Designable Formily adapter for your UI library. The official documentation in docs/guide/form-builder.md describes two primary distribution packages.


# For Ant Design users

npm install --save @designable/formily-antd

# For Alibaba Fusion Design users  

npm install --save @designable/formily-next

Import the required Ant Design CSS if using the AntD package:

import 'antd/dist/antd.less'

Constructing the Visual Editor

Building the interface requires assembling Designable widgets into a standard layout: a left resource panel, central canvas, and right property panel.

Initializing the Designable Engine

Create the designer engine with rootComponentName: 'Form' to establish Form as the root node. This configuration, referenced in packages/core/src/types.ts, ensures the engine recognizes Formily-specific metadata structures.

import { createDesigner, GlobalRegistry, Shortcut, KeyCode } from '@designable/core'

const engine = createDesigner({
  rootComponentName: 'Form',
  shortcuts: [
    new Shortcut({
      codes: [
        [KeyCode.Meta, KeyCode.S],
        [KeyCode.Control, KeyCode.S],
      ],
      handler: (ctx) => {
        const schema = ctx.engine.getCurrentSchema()
        console.log(JSON.stringify(schema, null, 2))
      },
    }),
  ],
})

Registering Draggable Resources

Use ResourceWidget components to expose Formily fields as draggable items. Register internationalization labels via GlobalRegistry.registerDesignerLocales() to provide human-readable category titles.

import { ResourceWidget } from '@designable/react'
import { Input, Select, Card, ArrayCards, FormGrid } from '@designable/formily-antd'

GlobalRegistry.registerDesignerLocales({
  'en-US': {
    sources: {
      Inputs: 'Inputs',
      Layouts: 'Layouts',
      Arrays: 'Arrays',
    },
  },
})

// Inside your component:
<ResourceWidget title="sources.Inputs" sources={[Input, Select]} />
<ResourceWidget title="sources.Layouts" sources={[Card, FormGrid]} />
<ResourceWidget title="sources.Arrays" sources={[ArrayCards]} />

Assembling the Workspace Layout

Wrap your application with the Designer provider and compose the layout using StudioPanel, CompositePanel (left sidebar), Workspace (center canvas), and SettingsPanel (right sidebar).

The canvas requires ComponentTreeWidget to render the live component tree, while ViewPanel containers support multiple view modes (Designable, JSON Tree, Markup, Preview).

import {
  Designer,
  StudioPanel,
  CompositePanel,
  Workspace,
  WorkspacePanel,
  ToolbarPanel,
  ViewportPanel,
  ViewPanel,
  SettingsPanel,
  ComponentTreeWidget,
  OutlineTreeWidget,
  HistoryWidget,
  DesignerToolsWidget,
  ViewToolsWidget,
} from '@designable/react'
import { SettingsForm } from '@designable/react-settings-form'

return (
  <Designer engine={engine}>
    <StudioPanel logo={<div>Form Builder</div>} actions={<div />}>
      <CompositePanel>
        <CompositePanel.Item title="panels.Component" icon="Component">
          <ResourceWidget title="sources.Inputs" sources={[Input, Password, Select]} />
        </CompositePanel.Item>
        <CompositePanel.Item title="panels.OutlinedTree" icon="Outline">
          <OutlineTreeWidget />
        </CompositePanel.Item>
      </CompositePanel>

      <Workspace id="form">
        <WorkspacePanel>
          <ToolbarPanel>
            <DesignerToolsWidget />
            <ViewToolsWidget use={['DESIGNABLE', 'JSONTREE', 'MARKUP', 'PREVIEW']} />
          </ToolbarPanel>
          <ViewportPanel>
            <ViewPanel type="DESIGNABLE">
              {() => (
                <ComponentTreeWidget
                  components={{
                    Form,
                    Field,
                    Input,
                    Select,
                    Card,
                    ArrayCards,
                    FormGrid,
                  }}
                />
              )}
            </ViewPanel>
            <ViewPanel type="JSONTREE">
              {(tree, onChange) => <SchemaEditorWidget tree={tree} onChange={onChange} />}
            </ViewPanel>
            <ViewPanel type="PREVIEW">
              {(tree) => <PreviewWidget tree={tree} />}
            </ViewPanel>
          </ViewportPanel>
        </WorkspacePanel>
      </Workspace>

      <SettingsPanel title="panels.PropertySettings">
        <SettingsForm uploadAction="https://example.com/upload" />
      </SettingsPanel>
    </StudioPanel>
  </Designer>
)

Exporting the Generated Schema

The schema lives in Designable's internal graph. Retrieve the current JSON schema by calling engine.getCurrentSchema() on the engine instance, typically inside a shortcut handler or custom save button.

const schema = engine.getCurrentSchema()
// Returns the complete Formily JSON schema representing the visual form

Key Implementation Files

File Significance
packages/core/src/types.ts Defines the designable?: boolean interface that enables Designable integration.
docs/guide/form-builder.md Official guide documenting the builder workflow and component imports.
@designable/react Provides the UI widget library (external dependency).
@designable/formily-antd Supplies the Formily component set for Ant Design.

Summary

  • Install the @designable/formily-antd (or formily-next) package to access the visual builder components.
  • Initialize a Designable engine with rootComponentName: 'Form' to establish the proper metadata structure as defined in packages/core/src/types.ts.
  • Register Formily components (Input, Select, ArrayCards, etc.) via ResourceWidget to populate the draggable palette.
  • Compose the interface using Designer, StudioPanel, Workspace, and SettingsPanel widgets to create the canonical three-panel layout.
  • Export the final form schema using engine.getCurrentSchema() for persistence or runtime rendering.

Frequently Asked Questions

What is the relationship between Formily and Designable?

Designable is the underlying open-source visual editor framework that powers Formily's Form Builder. Formily provides the specific form component library (@designable/formily-antd) and the designable metadata flag in packages/core/src/types.ts that bridges Designable's engine with Formily's schema system.

Can I use the Form Builder with UI libraries other than Ant Design?

Yes. Alibaba maintains @designable/formily-next for Alibaba Fusion Design users. The architecture remains identical; you simply import components from the alternative package and adjust the CSS imports accordingly.

How do I save the form schema created in the visual builder?

Call engine.getCurrentSchema() on your Designable engine instance to retrieve the current JSON representation. You can trigger this inside a Shortcut handler (as shown in the createDesigner configuration) or bind it to a custom save button in the ToolbarPanel.

Where is the designable configuration defined in the Formily source?

The designable?: boolean property is defined in packages/core/src/types.ts within the IFormProps interface. This flag tells Formily to expose Designable-specific hooks and metadata when operating inside the visual builder context.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →