A visual form builder for ngx-formly that brings community efforts together. Build Angular forms with drag-and-drop editing, custom components, live previews, and Formly JSON export.
Try the builder at builder.formly.dev.
Netlify automatically deploys successful builds of main, including the version commits used for
new package releases. The demo can include changes ahead of the latest npm release. See the
release checklist for deployment verification.
The repository is the shared foundation for an official ngx-formly builder. It currently provides the Studio application, reusable editor libraries, multiple UI profiles, local persistence, and authoring documentation.
The project is preparing its first embeddable package contract as @ngx-formly/builder, with
companion packages under @ngx-formly/builder-*. No compatibility guarantee is made until the
first public prerelease. See
CONTRIBUTING.md before proposing public API changes.
The project originated from the community evaluation in ngx-formly discussion #4198. It uses Formly Studio as the initial authoring foundation and will incorporate the strongest engineering and schema workflows from the other community builders.
The application and documentation use ngx-formly Builder. Studio remains the reference
application's source-folder name. The Material UI profile includes the standard controls and the
builder's additional fields and layouts.
The demo is hosted at builder.formly.dev. Canonical/social metadata
and crawler files still reference formlystudio.com, while package
homepages and documentation links use docs.formlystudio.com.
The repository is ngx-formly/ngx-formly-builder.
When domains change, update both deployments, redirects, canonical/social URLs, sitemaps, crawler
files, the docs build's site setting and header links together. Local browser storage is tied
to an origin, so provide an export/import migration before a domain move. This branding change
preserves all formly-studio-* storage keys and the project's author and provenance attribution.
Use Node.js 24.15 or newer within the Node.js 24 release line and pnpm 10.25.0. The builder uses Angular 22 and Formly 11. PrimeNG 21 and PrimeUIX themes 2 retain their MIT licenses. Because PrimeNG 21 declares Angular 21 peers, Angular 22 consumers currently need the scoped pnpm overrides shown in the package-consumer fixture. Removing this compatibility requirement is a prerequisite for a stable public release.
pnpm install
pnpm devpnpm dev starts Studio at http://localhost:4200 and docs at http://localhost:4321.
Use pnpm start for Studio alone or pnpm start:docs for docs alone. Studio watches the
libraries through the source paths in tsconfig.json; no separate library watchers are needed.
Run pnpm dev:portless to start both apps through Portless, which assigns
free ports and provides named URLs at https://builder-studio.ngx-formly.localhost and
https://builder-docs.ngx-formly.localhost. On first use, Portless may request administrator access
to start its HTTPS proxy and trust its local certificate. Follow the URLs printed in the terminal
if you use a custom proxy configuration or a Git worktree.
Studio stores forms per browser origin, so export forms from http://localhost:4200 before
switching URLs, then import them at the new URL.
The pnpm workspace includes apps/*, libs/*, and libs/ui/*, with one root lockfile.
The package-consumer fixture stays outside the workspace so it tests packed libraries in isolation.
Run pnpm test, pnpm run lint, pnpm run check:docs, and pnpm run build to validate changes. The
build also verifies that every external library import is declared by its published package, packs
the libraries, and builds a clean Angular consumer from those tarballs. After installing Playwright
Chromium, run pnpm run check:packages:e2e to check the packaged editor in a browser.
apps/studio: hosted reference application.apps/docs: author and integration documentation.libs/state: headless document models, hierarchy operations, and persistence contracts.libs/core: editor shell, UI orchestration, and extension contracts.libs/ui/material: reusable Material runtime fields.libs/ui/builder-material: editor-only adapters for Material composite fields.
| Source | Package |
|---|---|
libs/core |
@ngx-formly/builder |
libs/state |
@ngx-formly/builder-state |
libs/ui/material |
@ngx-formly/builder-material-fields |
libs/ui/builder-material |
@ngx-formly/builder-material |
The builder name maps to the existing editor shell in libs/core; source directories, build
targets, and package boundaries stay the same. It is separate from @ngx-formly/core, the Formly
runtime dependency. The reusable Material fields use @ngx-formly/builder-material-fields to
distinguish them from the existing @ngx-formly/material adapter. The private app
workspaces use @ngx-formly/builder-studio and @ngx-formly/builder-docs. The isolated consumer
fixture is @ngx-formly/builder-package-consumer.
Existing consumers must use the package names above in their dependencies and TypeScript imports,
and import the stylesheet from @ngx-formly/builder/styles.css. Rebuild and install matching
tarballs for all packages. Previous package names have no compatibility aliases. Exported symbols
and saved forms are unchanged.
The Studio route uses the same component and provider intended for embedding. The complete package-consumer fixture runs against npm tarballs without Studio or workspace source imports.
The editor's CSS requires Tailwind 4 and its PostCSS plugin. Install the build dependencies in the consuming application:
npm install tailwindcss tailwindcss-primeui
npm install --save-dev @tailwindcss/postcss postcssAdd .postcssrc.json at the Angular application's root:
{
"plugins": {
"@tailwindcss/postcss": {}
}
}Import the packaged stylesheet from the application's global CSS:
@layer theme, base, primeng;
@import '@ngx-formly/builder/styles.css';
html,
body,
app-root {
display: block;
height: 100%;
margin: 0;
}The CSS entry includes Tailwind's base styles, editor styles, PrimeUI utilities, and class scanning
for the packaged editor, including its lazy dialogs. It also includes the layout utilities used
by the editor's Styling panel. It is Tailwind source CSS, so it must go through PostCSS rather than
a browser <link>. Give the builder's container an explicit height if it does not fill the page.
UI profiles may need their own styles, such as an Angular Material theme.
Load the Material Symbols Outlined icon font in index.html, as Studio does, or self-host that
font with its matching font-face and .material-symbols-outlined rules:
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0"
/>Register the PrimeNG theme and any optional UI profiles, then render the builder component:
import { ApplicationConfig, ChangeDetectionStrategy, Component } from '@angular/core';
import { FormlyBuilder, primengPreset, provideFormlyBuilder } from '@ngx-formly/builder';
import { definePreset } from '@primeuix/themes';
import Aura from '@primeuix/themes/aura';
import { providePrimeNG } from 'primeng/config';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [FormlyBuilder],
template: `<formly-builder class="block h-full" />`,
})
export class FormEditorPage {}
export const appConfig: ApplicationConfig = {
providers: [
providePrimeNG({
theme: {
preset: definePreset(Aura, primengPreset),
options: {
darkModeSelector: '.dark',
cssLayer: { name: 'primeng', order: 'theme, base, primeng' },
},
},
}),
provideFormlyBuilder({ libraries: [myFormlyLibrary] }),
],
};Use your own profile for myFormlyLibrary. If the host already configures PrimeNG, merge these
theme settings into its existing provider. Toggle the .dark class on an ancestor to use dark
mode. provideCoreTheme() remains available to hosts that also synchronize the code editor theme.
provideFormlyBuilder accepts an editor storage namespace, autosave settings, and a custom
FormStoreService implementation. The API remains provisional until the first public prerelease.
Use provideFormlyBuilder() without profiles for native HTML controls. Leaving UI Library
empty when creating or importing a form uses Vanilla: input, number, textarea, checkbox, select,
and field groups. Pass shared FormTemplate[] through formTemplates to offer examples that use
the selected library. Without this setting, the editor uses the templates configured in each profile.
Document models and persistence APIs can also be consumed without importing the editor UI:
import { createEmptyWorkspaceHierarchy, type FormStoreService } from '@ngx-formly/builder-state';Custom stores may optionally implement getRecoveryIssues$ and resetCorruptedStorage$. These
hooks let the builder show its backup and reset workflow when persisted data cannot be read. Stores
that manage recovery outside the builder can omit them.
Recovery backups include each issue's original value and its optional relatedEntries, which hold
any other stored values that reset will remove. The local store includes the workspace hierarchy
when resetting corrupted forms also removes that hierarchy. Resetting only a corrupted hierarchy
preserves the active form's unsaved edits.
@ngx-formly/builder-state provides Angular editing operations without PrimeNG, CDK or the shell.
Register provideBuilderEngine in a route or environment injector, then inject
BuilderEngineService. Use a different editorType for each independent storage namespace.
import { BuilderEngineService, provideBuilderEngine } from '@ngx-formly/builder-state';
const providers = [provideBuilderEngine({
editorType: 'survey-designer',
autoSave: true,
libraries: [{
id: 'survey',
fieldTypes: [{ name: 'input', displayName: 'Input', defaultConfig: {} }],
}],
})];
// In the configured Angular injection context:
// const engine = inject(BuilderEngineService);
// engine.addForm$('Survey', [], {}, 'survey').subscribe();
// engine.addField('input');
// engine.activePreviewFormFields() contains exported Formly fields.Autosave defaults to true, with a 3000 ms delay; set autoSave: false for explicit saves.
The provider accepts an optional formStore class and autoSaveDelay. It does not register Formly
runtime components. Headless hosts render their own controls and register their chosen Formly
runtime separately. BuilderFieldStateService holds transient per-field UI state without storage.
The engine owns document edits, selection, hierarchy, autosave and recovery. Its formSelected$
event reports completed loads or unloads; the shell uses it to update library and panel selection.
Existing shell consumers keep provideFormlyBuilder and CoreFormService. That provider exposes
the same engine and transient field-state instances through the state entry point. Do not also
register provideBuilderEngine in the same injector. Storage keys and document formats are unchanged.
See Asynchronous stores and editor lifecycle for custom-store contracts, error handling, and saving before closing the editor.