Getting Started
The headless libraries give you the engine and the plugin system — you own every pixel of the UI. An app depends on two packages: the adapter for your framework, and an engine.
Installation#
npm install @embedpdf/angular@next @cloudpdf/engine@nextThe Angular adapter ships each vertical as a secondary entry point — Angular’s native library modularity — with inject functions instead of hooks.
Your first viewer#
cloudEngine({ baseUrl }) creates the engine — synchronously and cheaply: it
holds an HTTP client and nothing else, so a module-scope
const engine = cloudEngine({ baseUrl }) is safe (even under SSR). Hand it to
<Viewer>; every open, render, and text call rides HTTPS to your CloudPDF
deployment. This is the whole app:
Loading live preview…
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { cloudEngine } from '@cloudpdf/engine';
import { EpdfViewer, injectDocumentId } from '@embedpdf/angular/runtime';
import type { EpdfInitialDocument, OpenInput } from '@embedpdf/angular/runtime';
import { EpdfPageTemplate, EpdfStage, stagePlugin } from '@embedpdf/angular/stage';
import { EpdfRenderLayer, renderPlugin } from '@embedpdf/angular/render';
const ebook: OpenInput = { kind: 'share', shareToken: 'shr_WGj1goAtlNN_fQ5OswPrbJQM' };
// Kernel readers live INSIDE <epdf-viewer>, where the host is injectable —
// and document UI is gated on having a document.
@Component({
selector: 'demo-workspace',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [EpdfStage, EpdfPageTemplate, EpdfRenderLayer],
template: `
@if (documentId()) {
<epdf-stage style="display: block; height: 100%">
<ng-template epdfPage>
<epdf-render-layer />
</ng-template>
</epdf-stage>
} @else {
<p>Loading…</p>
}
`,
})
export class Workspace {
readonly documentId = injectDocumentId();
}
@Component({
selector: 'demo-root',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [EpdfViewer, Workspace],
template: `
<epdf-viewer [engine]="engine" [plugins]="plugins" [initialDocuments]="initialDocuments">
<div style="height: 500px">
<demo-workspace />
</div>
</epdf-viewer>
`,
})
export class App {
// The engine is created synchronously and costs nothing until first use, so
// a field initializer is safe. The viewer warms it up when the kernel
// materializes; only opening a document does real work — the UI renders
// at t≈0.
readonly engine = cloudEngine({ baseUrl: 'https://engine.cloudpdf.com' });
readonly plugins = [stagePlugin(), renderPlugin()];
readonly initialDocuments: EpdfInitialDocument[] = [{ source: ebook }];
}Prefer the viewer to own the engine’s lifetime — created on mount, destroyed on
unmount? Pass a thunk instead: engine={() => cloudEngine({ baseUrl })}. See
the Engine getting started for tokens, public
shares, and the ownership model.