Skip to content

Public API ​

Angular has no forwardRef imperative handle the way React does. Instead, PowerPointViewerComponent's programmatic API is just public methods on the component instance, reached through a template reference variable or Angular's viewChild() signal query.

ts
import { Component, viewChild } from '@angular/core';
import { PowerPointViewerComponent } from 'pptx-angular-viewer';

@Component({
	selector: 'app-editor',
	standalone: true,
	imports: [PowerPointViewerComponent],
	template: `
		<button (click)="save()">Save</button>
		<button (click)="viewer().goNext()">Next Slide</button>
		<button (click)="viewer().undo()">Undo</button>
		<pptx-viewer #viewer [content]="content" [canEdit]="true" />
	`,
})
export class EditorComponent {
	readonly viewer = viewChild.required(PowerPointViewerComponent);

	async save(): Promise<void> {
		const bytes = await this.viewer().getContent();
		// persist `bytes` (a Uint8Array)
	}
}

Template reference vs viewChild

#viewer in the template plus @ViewChild(PowerPointViewerComponent) viewer!: PowerPointViewerComponent works too (see the package README); viewChild() is the modern signal-based equivalent used above. Either way you get the same component instance and the same methods.

Contract shared across bindings ​

The methods below implement the same PowerPointViewerAPI contract (defined in ooxml-ui/pptx) that React's PowerPointViewerHandle and Vue's defineExpose surface also implement - all three framework bindings expose an equivalent API surface, just through each framework's own idiom (React forwardRef handle, Vue defineExpose, Angular public methods).

ts
import type { PowerPointViewerAPI, ViewerMode } from 'pptx-angular-viewer';

Methods ​

Serialization ​

MethodSignatureDescription
getContent() => Promise<Uint8Array>Serialises the current document to .pptx bytes on demand. When editing, serialises the edited deck (templates merged back).
MethodSignatureDescription
goTo(index: number) => voidNavigate to a specific slide (zero-based). No-op when out of range.
goPrev() => voidNavigate to the previous slide.
goNext() => voidNavigate to the next slide.

Undo / Redo ​

MethodSignatureDescription
undo() => voidUndo the last editing action. No-op when nothing to undo.
redo() => voidRedo the last undone action.
canUndo() => booleanWhether an undo action is available.
canRedo() => booleanWhether a redo action is available.

Zoom ​

MethodSignatureDescription
getZoom() => numberGet the current zoom level (1 = 100%).
setZoom(level: number) => voidSet the zoom level (clamped to 0.2 - 3.0).
zoomIn() => voidZoom in by one step.
zoomOut() => voidZoom out by one step.
zoomReset() => voidReset zoom to 100%.

Mode ​

MethodSignatureDescription
getMode() => stringGet the current viewer mode: 'preview', 'edit', 'present', or 'master'.
setMode(mode: string) => voidSwitch mode programmatically. 'present' enters slideshow, 'master' enters template-edit mode, anything else returns to normal preview/edit.

Read-only state ​

MethodSignatureDescription
getActiveSlideIndex() => numberGet the zero-based active slide index.
setActiveSlideIndex(index: number) => voidSet the active slide (alias of goTo).
getSlideCount() => numberGet the total number of slides.
isDirty() => booleanWhether the document has unsaved changes.

Slide access ​

Slide methods return full PptxSlide objects from pptx-viewer-core with complete type information (elements, notes, transitions, animations, etc.).

MethodSignatureDescription
getSlides() => readonly PptxSlide[]Get all slides in the deck.
getSlide(index: number) => PptxSlide | undefinedGet a slide by zero-based index.
getActiveSlide() => PptxSlide | undefinedGet the currently active slide.

Slide manipulation ​

MethodSignatureDescription
addSlide(afterIndex?: number) => voidAdd a blank slide (after active by default).
deleteSlides(indexes: number[]) => voidDelete slides at indexes.
duplicateSlides(indexes: number[]) => voidDuplicate slides at indexes.
moveSlide(from: number, to: number) => voidMove a slide from one position to another.
toggleHideSlides(indexes: number[]) => voidToggle the hidden flag on slides.

Element access ​

Element methods return full PptxElement objects (discriminated union of text, shape, image, table, chart, connector, group, etc.) with complete type-specific properties.

MethodSignatureDescription
getElements(slideIndex?: number) => readonly PptxElement[]Get elements (active slide by default).
getElementById(elementId: string, slideIndex?: number) => PptxElement | undefinedGet element by ID.

Element manipulation ​

MethodSignatureDescription
updateElement(elementId: string, updates: Partial<PptxElement>) => voidPatch element properties.
updateElements(updates: readonly ElementUpdate[], options?: ElementUpdateOptions) => Promise<void>Update elements across slides in one undo step.
deleteElements(elementIds: string[]) => voidDelete elements by ID.
duplicateElement(elementId: string) => string | undefinedDuplicate; returns new element ID.

Inserting an element ​

addElement(element: PptxElement): string | undefined appends a defensive copy to the active editable slide and selects it, returning its fresh ID. Coordinates are preserved; group descendants also receive fresh IDs. Pending text is committed through the existing editor path, with normal dirty-state and Undo/Redo behavior. Synchronous edits may share a history entry, but all insertions are retained. It returns undefined while loading, after a load error, without an active slide, or in read-only/protected, preview, presentation, or template/master editing modes.

Use a self-contained model or one from the current document. With a loaded viewer in edit mode:

ts
import { createImageElement } from 'pptx-viewer-core';

const image = createImageElement(pngDataUrl, { x: 40, y: 40, width: 160, height: 90 });
const insertedId = this.viewer().addElement(image);

This method does not install clipboard listeners, fetch remote URLs, choose image dimensions, or import another document's relationships. A host-owned paste handler can read an image and call it. For a new data-URL image, use the factory above without inventing an imagePath, which denotes an existing archive part.

Loading a local image ​

The package also exports createImageElementFromFile(file, canvasSize, signal?). Given a local File or Blob, the slide size in pixels, and an optional AbortSignal:

ts
import { createImageElementFromFile } from 'pptx-angular-viewer';

const image = await createImageElementFromFile(file, canvasSize, signal);

The helper preserves the image bytes and returns a centred ImagePptxElement, fitted to the slide without upscaling. It resolves null for invalid/unreadable images or dimensions, cancellation, or unavailable browser APIs. The helper does not use browser APIs until called; decoding requires those APIs.

This only constructs an element: it does not change a deck, history, selection, or clipboard. After await, verify that the same document and destination slide are still active and editable, then pass a non-null result to addElement. Abort pending work when that destination is abandoned. A slide ID alone is not a document identity, and decoding success does not guarantee that every browser image format round-trips in PowerPoint. No automatic paste listener is installed.

Selection ​

MethodSignatureDescription
getSelectedElementIds() => string[]Get IDs of currently selected elements.
selectElements(ids: string[]) => voidProgrammatically select elements by ID.
clearSelection() => voidClear the current selection.

UI customization ​

The handle also carries the whole ViewerCustomizationApi, so the chrome can be customised while the viewer runs. Each call re-renders the affected UI immediately.

ts
this.viewer()?.hideRibbonTab('draw');
this.viewer()?.lockSetting('general.userName', 'Ada Lovelace');
this.viewer()?.hideContextMenuCommand('delete');
this.viewer()?.remapShortcut('duplicate', 'Mod+Shift+D');
this.viewer()?.setFeatureEnabled('ai', false);
this.viewer()?.setPanelVisible('notes', false);
this.viewer()?.updateCustomization({ hiddenDialogs: ['print'] });
const current = this.viewer()?.getCustomization();
MethodEffect
getCustomization() / setCustomization(c) / updateCustomization(patch) / resetCustomization()Read, replace, merge or clear the whole ViewerCustomization.
hideRibbonTab / showRibbonTab, hideToolbarButton / showToolbarButtonRibbon tabs and top-level toolbar buttons.
hideOptionsPage, hideOptionsSection, hideSetting (and show*)File > Options pages, sections and settings.
lockSetting(id, value, hidden?) / unlockSetting(id) / setSettingDefault(id, value)Pin a setting (read-only or hidden) or set a host default.
hideBackstagePage / hideBackstageCard (and show*)File tab pages and action cards.
hideContextMenuCommand / hideCanvasContextMenuCommand (and show*)Element and empty-canvas right-click entries.
disableShortcut / enableShortcut / remapShortcutEditor keyboard shortcuts.
setPanelVisible, setFeatureEnabled, setDialogAvailablePanels, feature areas (AI, collaboration, ...) and dialogs.

The full id reference and recipes are in the UI Customization guide.

Example: external controls ​

ts
@Component({
	template: `
		<button (click)="viewer().goPrev()">Prev</button>
		<button (click)="viewer().goNext()">Next</button>
		<span>Slide {{ viewer().getActiveSlideIndex() + 1 }}</span>
		<span>{{ viewer().getActiveSlide()?.elements?.length }} elements</span>
		<button (click)="viewer().zoomIn()">Zoom In</button>
		<button (click)="viewer().zoomOut()">Zoom Out</button>
		<button (click)="viewer().undo()" [disabled]="!viewer().canUndo()">Undo</button>
		<button (click)="viewer().addSlide()">Add Slide</button>
		<pptx-viewer #ref [content]="content" [canEdit]="true" />
	`,
})
export class ToolbarComponent {
	readonly viewer = viewChild.required(PowerPointViewerComponent, {
		read: PowerPointViewerComponent,
	});
}

getContent vs contentChange

getContent() is a pull API: serialise on demand, e.g. when a Save button is clicked. contentChange is a push event that fires with fresh bytes as the document changes. Use whichever fits your save model; they return equivalent Uint8Array content.

Openable file kinds ​

The package root re-exports the shared answer to "can the viewer open this file?", so a host's drop target and its <input accept> cannot disagree with the loader. Hand-rolled endsWith chains drift: every demo in this repo once shipped .pptx,.ppt,.json, which refused on drop a .pptm that File > Open inside the viewer accepted without complaint.

ts
import {
	PPTX_OPEN_ACCEPT,
	PRESENTATION_OPEN_EXTENSIONS,
	isSupportedPresentationFile,
	isLegacyBinaryPresentation,
	presentationBaseName,
	savedPresentationFileName,
	type SavedPresentationFormat,
} from 'pptx-angular-viewer';
ExportTypeDescription
PPTX_OPEN_ACCEPTstringReady-made <input type="file" accept> value: .pptx,.ppsx,.pptm,.potx,.ppt,.json.
PRESENTATION_OPEN_EXTENSIONSreadonly string[]The same list unjoined, for a drop target that wants to test extensions itself.
isSupportedPresentationFile(name?: string | null) => booleanCheap pre-filter for a picked or dropped file name. Extension-only; the real answer is the loader's sniff.
isLegacyBinaryPresentation(name?: string | null) => booleanTrue for the binary PowerPoint 97-2003 family (.ppt / .pps / .pot), which the viewer reads but never writes.
presentationBaseName(name?: string | null, fallback?: string) => stringThe file-name stem, directories and any loadable extension removed (a path like decks/report.ppt becomes report).
savedPresentationFileName(name?: string | null, format?: SavedPresentationFormat) => stringThe name a saved copy should be offered under: report.ppt becomes report.pptx.
SavedPresentationFormat'pptx' | 'ppsx' | 'pptm'The formats the save path can produce. Binary .ppt is deliberately absent: output is always OpenXML.

savedPresentationFileName is the one that matters on Save As. Output is always an OpenXML package, so keeping a legacy source extension would hand the user a .ppt whose bytes are a ZIP, which PowerPoint refuses to open.

Released under the Apache-2.0 License.