Zoom and fit to screen
Fit the document to the viewport, control zoom from your UI with useZoom, and let the comments pane shrink the page instead of covering it.
The editor fits the page to its container by default. A container wide enough for the page renders at 100%. A narrower container shrinks the document instead of creating a horizontal scrollbar.
The two modes
Zoom has a value and a mode. The value is the scale the pages paint at; the mode is where that value comes from.
| Mode | Behavior |
|---|---|
'auto' (default) | Fit the page width, between 50% and 100%. Shrinks a page that does not fit, leaves one that does. |
{ type: 'fit', fit: 'pageWidth' } | Fit the page width in both directions, so a wide window magnifies the page. |
{ type: 'fixed' } | Hold whatever zoom is set to. This keeps a fixed scale (the behavior before fit modes). |
<DocxEditor document={bytes} /> {/* auto */}
<DocxEditor document={bytes} zoomMode={{ type: 'fit', fit: 'pageWidth' }} />
<DocxEditor document={bytes} zoom={1} zoomMode={{ type: 'fixed' }} /><!-- auto -->
<DocxEditor :document="bytes" />
<DocxEditor :document="bytes" :zoom-mode="{ type: 'fit', fit: 'pageWidth' }" />
<DocxEditor :document="bytes" :zoom="1" :zoom-mode="{ type: 'fixed' }" />Passing zoom on its own also means fixed, so an app that pinned a scale keeps it.
Fit mode updates when the container size changes. Resizing the window, opening the comments pane, or docking the navigation pane changes the space beside the page. The engine updates the scale without additional host code.
Setting a level ends the fit. A fixed zoom replaces fit mode. Container resize must not override an explicit scale.
Driving it yourself
useZoom returns zoom state and controls in one hook.
import { useZoom } from '@docx-editor.dev/react';
function ZoomControl() {
const { zoom, isFit, auto, zoomIn, zoomOut, canZoomIn, canZoomOut } = useZoom();
return (
<div>
<button onClick={zoomOut} disabled={!canZoomOut}>
−
</button>
<span>{Math.round(zoom * 100)}%</span>
<button onClick={zoomIn} disabled={!canZoomIn}>
+
</button>
<button onClick={auto} aria-pressed={isFit}>
Fit
</button>
</div>
);
}<script setup lang="ts">
import { useZoom } from '@docx-editor.dev/vue';
const { zoom, isFit, auto, zoomIn, zoomOut, canZoomIn, canZoomOut } = useZoom();
</script>
<template>
<div>
<button type="button" :disabled="!canZoomOut" @click="zoomOut">−</button>
<span>{{ Math.round(zoom * 100) }}%</span>
<button type="button" :disabled="!canZoomIn" @click="zoomIn">+</button>
<button type="button" :aria-pressed="isFit" @click="auto">Fit</button>
</div>
</template>The Vue composable returns computed refs. Destructured bindings unwrap in the template, so
read them with .value only in script code.
| Member | What it does |
|---|---|
zoom | The resolved scale. 1 is 100%. |
mode, isFit | Where the scale came from. Render a control's selected state from these, not from zoom. |
setZoom(n) | A fixed scale. Leaves any fit. |
setMode(m) | 'auto', a fit, or { type: 'fixed' }. |
auto(), fitToWidth() | The two fits, by name. |
reset() | Reset to fixed 100% zoom. |
zoomIn(), zoomOut() | Move to the next preset in levels. |
canZoomIn, canZoomOut | Whether a higher or lower preset remains. |
Render the selected state from mode, not from zoom. A menu that ticks the level matching the percentage marks "75%" as selected while fit mode still owns the scale.
The packaged toolbar's zoom control already does all of this: Automatic and Fit width sit above the preset levels, and the tick follows the mode rather than the percentage.
It ticks those two modes and the preset levels — the modes the menu can select. A fit with bounds of your own is not one of them, so the menu shows the resolved percentage with nothing ticked, rather than marking a preset that would replace custom fit bounds on click.
Comments, and narrow screens
The comments rail reserves a gutter beside the page. Under a fit that gutter comes out of the document's width, so opening comments shrinks the page rather than pushing it off screen: the two sit side by side and both stay readable.
Below a container width, reserving the rail width no longer keeps the page readable. The rail takes a fixed 316px whether or not the container can spare it. On a phone with comments open, fit would shrink the page below a readable width. So 'auto' has a floor of 50%: below that the page keeps a legible size and the container scrolls sideways, which matches the usual layout response when content exceeds the container.
Set your own floor if 50% is not where you want it:
<DocxEditor document={bytes} zoomMode={{ type: 'fit', fit: 'pageWidth', minZoom: 0.35 }} /><DocxEditor :document="bytes" :zoom-mode="{ type: 'fit', fit: 'pageWidth', minZoom: 0.35 }" />Without an adapter
Zoom APIs are on the engine. Every host calls the same methods:
editor.setZoomMode('auto');
editor.getZoom(); // 0.79 on a container too narrow for the page
editor.getZoomMode(); // { type: 'fit', fit: 'pageWidth', minZoom: 0.5, maxZoom: 1 }
editor.setZoom(1.5); // leaves the fit
editor.getZoomMode(); // { type: 'fixed' }snapshot() carries zoom and zoomMode, and both fire on selectionChange — including when the editor refits itself after a resize, so a subscriber never shows a stale percentage.
Chrome slot reference
Reference every editor chrome slot and its React and Vue toolbar part across default, contextual, menu, dialog, and header or footer surfaces.
Content controls
Find and fill Word content controls by tag or id. Set text, dropdown, checkbox, and date values, from inside the editor or from a server-side script.