Report designer
Build visual report and document layouts your backend fills with data at render time.
PageKit β the self-hosted GrapesJS site builder, sold as source. Get early access
Build a visual drag-and-drop page builder for Angular with reusable blocks, components, templates, responsive editing and your own publishing workflow.
26k+
GitHub stars
1.4M+
npm downloads / month
100+
Plugins on GJS.Market
$0
License fee, always
Three real GrapesJS editors, loaded only when you ask for them. None of these demos is an Angular application β and that is exactly the point. GrapesJS renders into a container element it owns, so the editing surface looks and behaves the same whatever framework hosts the page around it.
The stock editor: canvas, blocks, layer tree, style manager and device switcher. This is the foundation you start from before adding a single block of your own.
Loads a live third-party editor from grapesjs.com.
Building a page builder takes much more than a few Angular components. A production-ready visual editor needs every one of these before anyone can ship a page with it:
GrapesJS provides the visual editing foundation for most of that list, so your Angular application can spend its budget on your product and your business logic instead. The last two β where projects are stored and how pages go live β stay yours, because they are the parts that have to match your infrastructure.
GrapesJS core is open source under the BSD-3-Clause licence, version 0.23.6, with no licence fee at any scale.
Explore GrapesJSThe same engine, pointed at six different products. What changes between them is your content model, your blocks and your publishing target β not the editor.
Let content teams edit pages visually inside your CMS instead of filling in a form and hoping the layout survives.
Headless CMS editorGive marketing a visual editor for campaign pages so a new landing page stops being a developer ticket.
Landing page builderLet users assemble custom forms from your own field components, with validation rules your application already understands.
Form componentsCreate and manage email templates visually, with the table-based markup email clients still require.
Email template builderBuild visual report and document layouts your backend fills with data at render time.
Give every customer their own branded editing environment that looks like part of your product, not a bolted-on tool.
White-label page builderThe editor is one route inside your application, not a replacement for it. Everything above the editing layer stays exactly where Angular teams already put it.
Everything that makes your product yours, unchanged.
A lazy-loaded route, a component that owns the container, and a service that owns the editor instance.
The visual editing engine, running inside the container your component provides.
Where project data, uploads and published output actually live.
Angular owns your application. GrapesJS powers the visual editing layer.
Nothing in the top or bottom tier is provided by the editor. That boundary is what keeps the integration shallow enough to remove later β the editor never becomes the thing your product is built around.
Read the Angular integration guideEight subsystems that come with the engine. Each is an API you configure, not a black box you accept as-is.
Users build pages by dragging components onto the canvas, reordering them and nesting them where you allow it.
Define reusable component types with their own traits, rules about what can be dropped inside them, and your own behaviour.
Give users predefined sections and layouts in a palette rather than a list of raw HTML elements.
Let users customise typography, spacing, colour and layout through property panels you choose and constrain.
Preview and restyle a page per breakpoint, using device widths you define rather than a fixed set.
Manage images and other project assets through an asset manager you can point at your own storage.
Save finished pages as reusable starting points so the next page begins somewhere other than empty.
Get clean HTML and CSS out of the editor, or read the project JSON and render it however your application prefers.
What is deliberately not on this list: hosting, a CMS, a permission model and publishing infrastructure. Those belong to your application, and the sections below say how they connect.
A generic website builder is rarely the product anyone wants. Every layer of the editor can be replaced with something that matches your application instead.
Each layer narrows the editor towards your content model. By the last one, users are composing your product β not a website.
Register component types that mirror your own domain objects, expose only the traits your backend can act on, and put them in the block palette under your own categories. Users then work with a pricing table or a product grid that your API already understands, rather than with arbitrary markup you have to parse later.
// Your content model, not a generic website element.
editor.Components.addType('pricing-table', {
isComponent: (el) => el.dataset?.gjsType === 'pricing-table',
model: {
defaults: {
tagName: 'section',
droppable: false,
traits: ['plan', 'currency', 'billingPeriod'],
},
},
});
editor.Blocks.add('pricing-table', {
label: 'Pricing',
category: 'Your design system',
content: { type: 'pricing-table' },
});A component type and the block that inserts it. The trait names become the fields your backend reads.
The difference between an editor people use and one they abandon is usually what is in the palette on day one.
Your blocks
Don't make users start from a blank canvas.
Create reusable blocks and templates that match your application's design system, so every page a user builds is already on-brand and already responsive. GJS.Market ships block sets and template managers you can install instead of authoring the first fifty from scratch.
Browse Blocks & TemplatesGrapesJS serialises a project to JSON and hands it to a storage adapter. What that adapter does is entirely yours.
The editor never talks to your database. It calls the adapter you registered, and the adapter calls the API you already have.
editor.Storage.add('angular-backend', {
async load() {
return firstValueFrom(this.http.get(`/api/pages/${this.pageId}`));
},
async store(data) {
return firstValueFrom(this.http.put(`/api/pages/${this.pageId}`, data));
},
});
grapesjs.init({
container,
storageManager: { type: 'angular-backend', autosave: true, stepsBeforeSave: 5 },
});A custom storage adapter wired to your API. Nothing here is specific to GJS.Market β it is the editor's documented storage contract.
Components, styles, pages and assets serialise to a JSON document you can store in any column or collection.
The storage manager can save after a configurable number of changes rather than only on an explicit action.
Register a custom adapter and route load and store through Angular's HttpClient, with your own interceptors and auth headers.
Because each save is a document, keeping history is a backend decision β the editor does not need to know it happened.
Export the rendered markup alongside the project JSON when your delivery path needs static output rather than a re-render.
A published page is a separate record with its own lifecycle. Keep it apart from the draft the editor writes to.
You control where project data is stored.
Authoring and publishing are different problems with different failure modes. The editor solves the first one; the second stays in your infrastructure, where your caching, permissions and rollbacks already live.
Where published output can go
Write the output back into the content system your organisation already runs.
Post the project or the rendered markup to an endpoint that owns validation and permissions.
Render pages to files at publish time so the live page carries none of the editor's runtime.
Store, transform and serve the output through the same path your application already uses to serve its pages.
Push published assets and markup to the edge, with cache invalidation you control.
Trigger your existing build or deploy pipeline from the publish action.
GrapesJS handles authoring. Your infrastructure can handle publishing.
One deployment of your Angular application, one editor, and a separate world of pages for every customer in it.
Angular SaaS
Org A
Org B
Org C
None of this is a GrapesJS feature. The editor has no concept of a tenant: it loads the project it is given and stores the project it is handed back. Tenancy is something your Angular application and your backend implement β which is also why it can match the isolation model you already have.
Explore SaaS Page BuilderNothing about the editor has to look like the editor. Every surface a user touches is configurable, replaceable or removable.
Turn a visual editor into a native part of your Angular product.
Explore White-Label Page BuilderThe short version, in four steps. The complete guide β lifecycle details, wrappers, zoneless change detection, production concerns β lives on its own page and goes much further than this.
Add the editor to your application. It is a plain npm package with no Angular-specific build step.
Keep the editor instance in an injectable service so the component stays thin and the instance is easy to share, mock and tear down.
The container element must be in the DOM before the editor is created, because GrapesJS measures it immediately.
Call destroy when the route is left. Without it the editor keeps its DOM listeners and the next navigation leaks an instance.
npm install grapesjsOne dependency. No Angular-specific wrapper is required.
import { Injectable, NgZone, inject } from '@angular/core';
import grapesjs, { type Editor } from 'grapesjs';
@Injectable({ providedIn: 'root' })
export class PageBuilderService {
private readonly zone = inject(NgZone);
private editor?: Editor;
create(container: HTMLElement): Editor {
// GrapesJS binds its own DOM listeners to the canvas. Creating it outside
// Angular keeps every drag frame from scheduling change detection.
this.editor = this.zone.runOutsideAngular(() =>
grapesjs.init({
container,
height: '100%',
fromElement: false,
storageManager: false,
})
);
return this.editor;
}
destroy(): void {
this.editor?.destroy();
this.editor = undefined;
}
}The service owns the instance and its lifetime; the component owns only the container.
import {
AfterViewInit,
Component,
ElementRef,
OnDestroy,
inject,
viewChild,
} from '@angular/core';
import { PageBuilderService } from './page-builder.service';
@Component({
selector: 'app-page-builder',
standalone: true,
template: '<div #canvas class="builder"></div>',
styles: '.builder { height: 100vh; }',
})
export class PageBuilderComponent implements AfterViewInit, OnDestroy {
private readonly builder = inject(PageBuilderService);
private readonly canvas = viewChild.required<ElementRef<HTMLElement>>('canvas');
ngAfterViewInit(): void {
// The container has to be in the DOM first: GrapesJS measures it on init.
this.builder.create(this.canvas().nativeElement);
}
ngOnDestroy(): void {
// Without this the editor keeps its listeners after the route changes.
this.builder.destroy();
}
}Create after the view exists, destroy when it goes away. That pair is most of the integration.
Need the complete Angular integration guide?
Wrapper options, zoneless change detection, lazy-loaded editor routes, asset handling and the production checklist are covered end to end there.
Read the Angular Integration GuideGrapesJS emits its own events, and those events do not come from Angular. Coordinating the two is a few lines, but skipping it produces the two bugs every integration hits first.
editor.on('storage:end:store', () => {
// Editor events fire outside Angular because the editor was created there.
// Re-enter the zone before touching state the template renders.
this.zone.run(() => this.lastSavedAt.set(new Date()));
});Re-entering the zone in the one handler that updates rendered state.
Create the editor inside runOutsideAngular so canvas interaction does not schedule change detection on every frame, then re-enter the zone in the handful of event handlers that actually update state your template renders. On a zoneless application the same handlers update signals instead, and the outer wrapper is no longer needed.
More on Angular lifecycle and zonesGrapesJS needs a browser DOM. Under Angular SSR or Angular Universal that means the editor is created in the browser only β the route around it still renders on the server as normal.
Guard the initialization with isPlatformBrowser and return early on the server. The rest of the route is unchanged: guards, resolvers and the surrounding markup keep their server-rendered behaviour, and only the editor container arrives empty.
import { PLATFORM_ID, inject } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
export class PageBuilderComponent implements AfterViewInit {
private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
ngAfterViewInit(): void {
// There is no DOM on the server and GrapesJS needs one, so the editor is
// created in the browser only. The rest of the route still renders on the
// server as usual.
if (!this.isBrowser) return;
this.builder.create(this.canvas().nativeElement);
}
}The whole SSR adjustment: one platform check before the editor is created.
The integration is ordinary Angular code, which is the main thing worth saying about it.
The editor ships its own type definitions, so the instance, its configuration and its events are typed at the call site.
Creation and teardown hang off ngAfterViewInit and ngOnDestroy β no manual bootstrapping outside the component tree.
Nothing in the integration depends on runtime template compilation, so the editor route builds like any other lazy-loaded route.
Where SSR is in play, only the editor creation is browser-guarded; the rest of the component compiles and renders normally.
Every capability below has to exist before a visual editor is usable. The only question is which of them you write yourself.
| Capability | From scratch | GrapesJS |
|---|---|---|
| Visual canvas | Build | Included |
| Drag & drop | Build | Included |
| Components | Build | Included |
| Blocks | Build | Extensible |
| Styling | Build | Included |
| Responsive editing | Build | Included |
| Assets | Build | Extensible |
| Templates | Build | Extensible |
| Storage | Build | Extensible |
| Export | Build | Extensible |
| Angular integration | Build | Integrate |
"Extensible" means the subsystem exists and has a documented API you point at your own implementation β not that it arrives pre-wired to your backend. Verified against GrapesJS 0.23.6 on 2026-09-03.
Build your Angular product. Don't rebuild the visual editing engine.
The stack a working builder ends up with. GrapesJS covers the first layer; the rest is yours to assemble, install or buy.
The engine gives you the editing surface. Everything a specific product needs on top of it β the block palette, the template system, rich text, persistence, the exit path to production β is where GJS.Market plugins come in. Every listing below is a real product, priced as shown.
Problem: a fresh editor has an empty palette, and nobody builds a page out of a bare <div>.
Browse this categoryThe starting palette: columns, text, images, links and video, so the canvas is usable on day one.
Tailwind-based blocks, so pages users build come out matching a utility design system you already use.
Bootstrap 5 grid and component blocks for teams whose design system is already Bootstrap.
One header edited once and reused across every page, instead of copies drifting apart.
Problem: users need somewhere to start, and multi-page projects need a manager the editor does not ship.
Browse this categoryA template library inside the editor, so a new page starts from a finished layout.
Multi-page projects with a page list, so a builder handles a site rather than a single document.
Lets users save their own sections as reusable blocks β your palette grows without you shipping anything.
Project browsing and management around the editor, for teams working on more than one thing at a time.
Problem: everyone assumes rich text and working forms are built in. Neither is, beyond the basics.
Browse this categoryForm components with inputs, selects and validation traits, ready to submit to your endpoints.
Replaces the built-in rich text editor with CKEditor 5 for teams that need serious text editing.
The same, with TinyMCE 6 β familiar to anyone coming from a traditional CMS.
Extra formatting controls on the default rich text editor without adding a third-party dependency.
Problem: the prototype that never persisted anything is the one that never shipped.
Browse this categoryLocal persistence in the browser: useful for drafts, offline editing and preview environments.
Stores projects in Directus, if a headless backend is already part of your stack.
Downloads a page as a ZIP of HTML, CSS and assets β the simplest possible export path.
Publishes straight to Netlify, for products whose output is a hosted static site.
Or start from a category
Both columns end with a working builder. They differ in how much of it you are still maintaining in two years.
GrapesJS provides the visual editing foundation. GJS.Market plugins let you extend your builder with additional capabilities instead of building every feature internally.
Five recurring shapes, and what each of them is really buying with a visual editor.
Add visual editing to a product whose customers currently ask support to change a page for them.
Build a custom editing environment per client instead of handing over a CMS nobody wanted.
Add visual editing without spending a roadmap year writing an editor engine from scratch.
Let marketers create and change pages without a developer in the loop for every headline.
Create controlled internal editing workflows, where what can be edited is as important as what can be built.
Four ways to ship a visual editor. They overlap, but they start from different constraints β and picking the wrong one shows up late.
Build a visual editor inside your own Angular application, owned by your team and shaped by your content model. That is this page.
Embed the editor into an application that already exists, with minimal surface area between the two.
Embeddable page builderBuild a customer-facing visual editing product, with tenancy, plans and per-customer publishing.
SaaS page builderMake the editor look and behave like your own product, down to the vocabulary in its panels.
White-label page builderBuilding the same thing on another framework? The argument is identical for React, Next.js and Vue β only the lifecycle code changes. React page builder, Next.js page builder, Vue page builder.
An editor is a heavy application and a published page is not. Treating them as one bundle is the mistake worth avoiding early.
Users who never open the builder should never download it. A lazy route keeps the editor out of your main bundle.
Create the editor outside Angular's zone and re-enter it only in the handlers that update rendered state.
Paginate the asset manager against your API rather than handing it several thousand images at once.
Create the instance when the editor is actually shown, not when the surrounding component mounts.
Published output is HTML and CSS. Nothing about the editor needs to ship with it.
The editor runtime and the published page do not need to have the same performance requirements.
A visual editor accepts user-authored content and writes it back to your system. Every one of these belongs on the server side of that exchange.
Check on every load, store and publish call whether this user may act on this project.
Resolve the tenant from the session, never from a parameter the client can change.
Validate type and size server-side, and serve uploads from an origin that cannot execute them.
The storage adapter runs in the browser. Its endpoints need the same authentication as the rest of your API.
Where editors may embed custom code, sanitise on the server before that markup is served to anyone else.
Publishing changes what the public sees. Rate-limit it, log it, and gate it behind its own permission.
Hiding a button changes the UI, not the API. Every rule the UI implies must also exist behind it.
Never rely only on client-side permissions.
Need help integrating, extending or customising GrapesJS inside your Angular application? Our team can help with integration, custom plugins, UI customisation and production implementation.
A visual editor inside an Angular application that lets users assemble pages by dragging components onto a canvas instead of writing markup. The Angular app owns routing, authentication and data; the editor owns the editing surface.
Yes. GrapesJS is framework-agnostic: it renders into a container element you give it, so it works inside an Angular component like any other DOM-based library.
No β it is the visual editing engine an Angular page builder is built on. There is no official Angular wrapper; you integrate the core library directly, which is a component and a service.
Install the package, keep the instance in an injectable service, create it in ngAfterViewInit once the container is in the DOM, and destroy it in ngOnDestroy. The full guide covers wrappers, zones and production concerns.
Yes. Blocks are registered through the block manager with your own label, category and content, so the palette can contain only sections your product supports.
Yes. Component types are registered with their own traits, drop rules and behaviour, which is how the editor is narrowed from generic HTML down to your content model.
Yes. A saved project can be reloaded as the starting point for a new page. Template libraries and managers are also available as plugins if you would rather not build the UI.
Yes. Register a custom storage adapter whose load and store methods call your API through HttpClient, so your interceptors, auth headers and error handling apply as usual.
Yes. The editor produces a JSON document and never talks to a database itself, so where that document is stored is entirely a backend decision.
Yes, and it is one of the most common uses: a restricted block palette, on-brand templates and a publish action that writes to wherever your marketing pages are served from.
Yes. The editor replaces the form-based editing screen; your CMS keeps ownership of content types, workflow and permissions.
Yes. Register your own field components as component types with traits for validation and naming, so what users assemble maps onto a schema your backend understands.
Yes, but tenancy is your application's job. The editor has no concept of a tenant β your backend resolves which project, assets and templates the current user may see.
Yes. Panels, icons, colours, block categories and terminology are all configurable, and you can drive the editor from your own Angular UI through its command API.
The surrounding route renders on the server as normal; the editor itself is created in the browser only. Guard initialization with isPlatformBrowser and return early on the server.
Create the editor inside runOutsideAngular so canvas interaction does not trigger change detection constantly, then use NgZone.run inside the few event handlers that update state your template renders.
Yes. GrapesJS ships its own type definitions, so the editor instance, its configuration object and its events are typed in an ordinary Angular TypeScript codebase.
Yes. Plugins are functions that receive the editor and register components, blocks, commands or panels. GJS.Market lists free and commercial plugins for blocks, rich text, storage, assets and export.
Use Angular for your application and GrapesJS for the visual editing experience. Add your own components, blocks, templates, storage and publishing workflow β then extend the builder with GJS.Market plugins when you need more.
Install the editor, mount it on a container inside an Angular component, and have something on screen this afternoon.
Get StartedBlocks, templates, rich text, storage and export β install the capabilities your product needs instead of writing them.
Browse PluginsLifecycle, zones, SSR, wrappers and the production checklist, covered end to end on the integration page.
View Angular GuideYour Angular app. Your editor. Your product.