Angular
Use the standalone subpath (@tumaet/apollon). Angular hosts get the
editor with zero peer deps to install — React is bundled inside the
tarball.
import {
Component,
DestroyRef,
ElementRef,
afterNextRender,
inject,
input,
viewChild,
} from "@angular/core"
import { ApollonEditor, type UMLModel } from "@tumaet/apollon"
import "@tumaet/apollon/style.css"
@Component({
selector: "app-diagram-editor",
template: `<div #host style="width: 100%; height: 100%"></div>`,
})
export class DiagramEditorComponent {
readonly initialModel = input<UMLModel>()
private host = viewChild.required<ElementRef<HTMLDivElement>>("host")
constructor() {
const destroyRef = inject(DestroyRef)
afterNextRender(() => {
const editor = new ApollonEditor(this.host().nativeElement, {
model: this.initialModel(),
})
const subId = editor.subscribeToModelChange((model) => {
localStorage.setItem("diagram", JSON.stringify(model))
})
destroyRef.onDestroy(() => {
editor.unsubscribe(subId)
editor.destroy()
})
})
}
}
The editor mounts its own React tree inside the <div> you give it. Your
Angular code only sees the imperative API.
Why this shape (Angular 17.3+)
viewChild.required<…>(...)is the signal-based view query — a function you call to read the liveElementRef, statically guaranteed non-null with.required. It replaces the@ViewChilddecorator.afterNextRender(...)runs the callback once, after the first DOM commit, and is a no-op during server-side rendering. That removes the manualisPlatformBrowserguard and the wrong-hook choice ofngAfterViewInitfor "after the DOM is painted." See angular.dev — Side effects for non-reactive APIs.inject(DestroyRef).onDestroy(...)colocates teardown with setup — no class needs to implement theOnDestroylifecycle interface. See angular.dev — DestroyRef.standalone: trueis the Angular 19+ default; on 17/18 add it back.- No
type/mode/localein the minimal example — those are the editor's defaults, so passing them is noise. Pass them only to override.
The <div> must have an explicit height, or the editor renders blank — see
Troubleshooting.
Configuration
Pass options as the constructor's second argument:
import { ApollonEditor, ApollonMode, UMLDiagramType } from "@tumaet/apollon"
new ApollonEditor(this.host().nativeElement, {
type: UMLDiagramType.BPMN,
mode: ApollonMode.Assessment,
collaborationEnabled: true,
})
See the API reference for the full ApollonOptions table and
every imperative method on the ApollonEditor instance.
SSR / Angular Universal
The editor is client-only — it touches window at construction.
afterNextRender is already a no-op on the server, so the snippet above is
SSR-safe by construction. (If you keep the older ngAfterViewInit shape,
guard the call with isPlatformBrowser(this.platformId) instead.)