- Overview
- Anatomy
- Header
- Navigation
- Renderers
The DOCX Viewer renders a Word document with docx-preview directly — faithful, paginated pages (page size, margins, headers and footers), continuous scroll, zoom, fit-to-width, and download. It mirrors the PDF Viewer so the two are drop-in siblings.
It is built without manual page bookkeeping: the document blob loads through
React's use() with Suspense, docx-preview lays out the pages once, and
off-screen pages are skipped by the browser via CSS content-visibility — so a
long document only lays out and paints the pages near the viewport.
"use client";
import * as React from "react";
import { DocxViewer } from "@/components/ui/docx-viewer";
export function DocxViewerDemo() {
return (
// A 25-page report (explicit page breaks; the rendered count matches the
// document's own page count) so off-screen page skipping shows at scale.Installation
pnpm dlx shadcn@latest add @retab/docx-viewer
This pulls in docx-preview (and its single dependency, jszip). Everything is
resolved from the installed package by your bundler — there is no runtime CDN
call.
Usage
import { DocxViewer } from "@/components/ui/docx-viewer";
export function Example() {
return (
<DocxViewer
source={{ kind: "url", url: "/document.docx", fileName: "document.docx" }}
className="h-[600px]"
/>
);
}Performance
docx-preview renders the document to the DOM (not a canvas), which is already
cheap. On top of that, each page section gets content-visibility: auto with a
matching contain-intrinsic-size, so the browser skips layout and paint for
pages outside the viewport while keeping the scrollbar stable. Zoom is applied
with CSS zoom on the laid-out pages, so changing scale never re-parses the
document.
API Reference
| Prop | Type | Description |
|---|---|---|
source | UrlViewerSource | BlobViewerSource | Canonical DOCX source. URL sources load through fetch; Blob sources load directly from the Blob. |
scale | number | Optional fixed zoom; omit to fit page width to the container. |
controls | boolean | Show the zoom/download controls. Defaults to true. |
highlight | DocxTarget | null | A resolved target to highlight — a text span (located by content match) or a table cell (by index) — tinted via the CSS Custom Highlight API. Derive it from a source with the docx-source adapter's sourceToDocxHighlight. |
onVisiblePageChange | (page: number) => void | Fired with the 1-based page nearest the top of the viewport. |
onScrollProgressChange | (progress: number) => void | Fired with scroll progress in [0, 1]. |
header | ReactNode | Strip rendered directly below the controls. |
aside | ReactNode | Left rail rendered alongside the scrolling pages. |
bare | boolean | Drop the outer border/background so the viewer fills its container. |
className | string | Optional class on the viewer root element. |
Source
"use client";
import * as React from "react";
import { clearDocxDocumentResource } from "@/lib/docx-document-resource";
import { isResourceError, isViewerFormatError } from "@/lib/viewer-errors";
import {
createViewerResource,
type ViewerResource,
} from "@/lib/viewer-resource";
import { useIsClient } from "@/components/ui/use-is-client";
import { ViewerErrorBoundary } from "@/components/ui/viewer-error";