BuilderJS

Embed BuilderJS in Angular: the drag-and-drop page builder library

Looking for an Angular page builder library you can self-host and own outright? BuilderJS is a framework-agnostic, vanilla-JavaScript drag-and-drop editor for HTML email and landing pages that drops into any Angular component. It is not an npm package and has no module export — you load it as a global browser script that attaches window.Builder, then instantiate it inside your component's mount hook. This guide shows the exact, copy-paste mount pattern: render three container divs in your template, declare the global, and call new Builder() with CSS-selector strings in ngAfterViewInit. BuilderJS is purely the in-browser editor you embed — it builds and exports the markup; you bring your own sending, hosting, and publishing. It ships under a one-time CodeCanyon license (Regular $52 / Extended $99) with full source you self-host: no SaaS, no monthly fee, no per-seat pricing.

Mount it

import { Component, AfterViewInit } from '@angular/core';

// The global /builderjs/builder.js script attaches window.Builder.
// There is no npm package and no named export to import.
declare global {
  interface Window { Builder: any; }
}

@Component({
  selector: 'app-builder',
  template: `
    <div id="bjs-widgets"></div>
    <div id="bjs-canvas"></div>
    <div id="bjs-settings"></div>
  `,
})
export class BuilderComponent implements AfterViewInit {
  private builder: any;

  ngAfterViewInit(): void {
    if (this.builder) return; // instantiate exactly once
    this.builder = new window.Builder({
      mainContainer: '#bjs-canvas',     // required, a CSS selector string
      widgetsContainer: '#bjs-widgets',
      settingsContainer: '#bjs-settings',
    });
    this.builder.load(themeJson, themeTemplatesJson, themeConfigData, mediaUrl);
    // save: const json = this.builder.getData(); POST json to your backend
    // no destroy(): Angular discards the container DOM node on unmount
  }
}

Load BuilderJS as a global script, not an npm import

BuilderJS ships as a compiled browser bundle, not an ES module. Add the stylesheet and script to your index.html (or the angular.json scripts/styles arrays): <link rel="stylesheet" href="/builderjs/builder.css"> and <script src="/builderjs/builder.js"></script>. Loading the script attaches a single global, window.Builder. There is no named export, so never write import { Builder } from 'builderjs' — that module does not exist and will fail to resolve. Inside your TypeScript component, tell the compiler the global exists by declaring it on the Window interface (declare global { interface Window { Builder: any } }) and reference it as window.Builder. The constructor signature is new window.Builder({ mainContainer, widgetsContainer, settingsContainer }) where every option is a CSS selector string (for example '#bjs-canvas'), not a DOM node and not an Angular ViewChild ElementRef. mainContainer is required; the other two are optional sidebars.

Mount client-side inside ngAfterViewInit

BuilderJS is a DOM-mount bundle: it queries the selectors you pass and renders the editor into those live elements. That means it can only run in the browser, after Angular has painted the component's template — never during server-side rendering. Instantiate it in ngAfterViewInit, the hook that fires once the view's DOM exists. Your component template must render the three container nodes the editor mounts into: <div id="bjs-widgets"></div>, <div id="bjs-canvas"></div>, and <div id="bjs-settings"></div>. Pass those same ids as selector strings to the constructor. If you use Angular Universal/SSR, guard the instantiation behind a platform check (isPlatformBrowser) so it only runs in the browser. The selectors must resolve to elements that are already in the DOM by the time ngAfterViewInit runs.

Load a theme and persist with getData() / load()

After construction, populate the canvas by calling builder.load(themeJson, themeTemplatesJson, themeConfigData, mediaUrl) — exactly four positional arguments, in that order. themeJson is the page tree, themeTemplatesJson maps template names to HTML, themeConfigData holds fonts/colors/sizes, and mediaUrl is the base URL for relative asset paths. To save the user's work, call const json = builder.getData() and POST that JSON to your own backend route. To restore a saved design later, feed it straight back through builder.load(...) as the first argument. BuilderJS itself does no sending, hosting, or publishing — getData() hands you the editor state and the exported markup, and your application owns storage and delivery from there.

No destroy() — instantiate exactly once

BuilderJS has no destroy(), teardown(), or dispose() method, so never call builder.destroy(). When Angular tears down the component, the framework removes the host container DOM node and the editor goes with it — there is nothing to dispose manually. The only thing to manage is not constructing it twice. In plain Angular this is straightforward because ngAfterViewInit runs once per component instance, but if you share the React-style double-invoke concern (or hot-reload during development), guard instantiation with a boolean flag on the component so new window.Builder() runs exactly once. Hold the instance in a class field if you need to call getData() or load() again later.

Frequently asked questions

Explore