Skip to main content
SuperDoc works with Angular through direct DOM manipulation. No wrapper needed. Requires Angular 17.2+. viewChild() and input() are stable from Angular 19; developer preview before that. On older versions, use @ViewChild, @Input, and ngOnDestroy in place of inject(DestroyRef).

Install

npm install superdoc

Basic setup

import { Component, ElementRef, viewChild, AfterViewInit, inject, DestroyRef } from '@angular/core';
import { SuperDoc } from 'superdoc';
import 'superdoc/style.css';

@Component({
  selector: 'app-editor',
  template: `<div #editor style="height: 700px"></div>`,
})
export class EditorComponent implements AfterViewInit {
  private readonly editorRef = viewChild.required<ElementRef<HTMLDivElement>>('editor');
  private superdoc: SuperDoc | null = null;

  constructor() {
    inject(DestroyRef).onDestroy(() => this.superdoc?.destroy());
  }

  ngAfterViewInit() {
    this.superdoc = new SuperDoc({
      selector: this.editorRef().nativeElement,
      document: 'contract.docx',
      documentMode: 'editing',
    });
  }
}

Full component

A reusable editor component with mode switching and export:
import { Component, ElementRef, viewChild, input, AfterViewInit, inject, DestroyRef } from '@angular/core';
import { SuperDoc } from 'superdoc';
import 'superdoc/style.css';

@Component({
  selector: 'app-doc-editor',
  template: `
    <div class="controls">
      <button (click)="setMode('editing')">Edit</button>
      <button (click)="setMode('suggesting')">Review</button>
      <button (click)="setMode('viewing')">View</button>
      <button (click)="exportDoc()">Export</button>
    </div>
    <div #editor style="height: 700px"></div>
  `,
})
export class DocEditorComponent implements AfterViewInit {
  private readonly editorRef = viewChild.required<ElementRef<HTMLDivElement>>('editor');
  readonly document = input.required<File | string>();
  readonly user = input<{ name: string; email: string }>();

  private superdoc: SuperDoc | null = null;

  constructor() {
    inject(DestroyRef).onDestroy(() => this.superdoc?.destroy());
  }

  ngAfterViewInit() {
    this.superdoc = new SuperDoc({
      selector: this.editorRef().nativeElement,
      document: this.document(),
      documentMode: 'editing',
      user: this.user(),
      onReady: () => console.log('Editor ready!'),
    });
  }

  setMode(mode: 'editing' | 'viewing' | 'suggesting') {
    this.superdoc?.setDocumentMode(mode);
  }

  async exportDoc() {
    await this.superdoc?.export({ isFinalDoc: true });
  }
}

Handle file uploads

import { Component, ElementRef, viewChild, inject, DestroyRef } from '@angular/core';
import { SuperDoc } from 'superdoc';
import 'superdoc/style.css';

@Component({
  selector: 'app-upload-editor',
  template: `
    <input type="file" accept=".docx" (change)="onFileChange($event)" />
    <div #editor style="height: 700px"></div>
  `,
})
export class UploadEditorComponent {
  private readonly editorRef = viewChild.required<ElementRef<HTMLDivElement>>('editor');
  private superdoc: SuperDoc | null = null;

  constructor() {
    inject(DestroyRef).onDestroy(() => this.superdoc?.destroy());
  }

  onFileChange(event: Event) {
    const file = (event.target as HTMLInputElement).files?.[0];
    if (!file) return;

    this.superdoc?.destroy();
    this.superdoc = new SuperDoc({
      selector: this.editorRef().nativeElement,
      document: file,
      documentMode: 'editing',
    });
  }
}

Next steps