integrate-file-viewer
cognitedata/builder-skills
Integrate CogniteFileViewer into Flows apps to preview CDF files (PDFs, images, text) with zero manual setup.
What is integrate-file-viewer?
Adds CogniteFileViewer component to Flows apps for previewing CDF files including PDFs, images, and text. Use this skill whenever you need file preview functionality—it handles all dependencies, Vite configuration, worker setup, and component integration automatically.
- Copy file-viewer library files into src/cognite-file-viewer/
- Install react-pdf dependency with correct pdfjs-dist bundling
- Configure Vite to exclude pdfjs-dist from pre-bundling
- Provide CogniteFileViewer component with zoom, pan, rotation, and touch gestures
- Support PDF, Office documents, images, and text file rendering
- Enable diagram annotation overlay for data-modelled files (instanceId sources)
How to install integrate-file-viewer
npx skills add https://github.com/cognitedata/builder-skills --skill integrate-file-viewer- Flows app with existing React and @cognite/sdk setup
- Package manager (pnpm, npm, or yarn) configured in the app
- For pnpm users: either add pdfjs-dist as direct dependency or configure public-hoist-pattern in .npmrc
How to use integrate-file-viewer
- 1.Read package.json to detect package manager and vite.config.ts to understand current Vite setup
- 2.Copy all files from code/ directory into src/cognite-file-viewer/ (types.ts, mimeTypes.ts, fileResolution.ts, useViewport.ts, useFileResolver.ts, useDocumentAnnotations.ts, DocumentAnnotationOverlay.tsx, CogniteFileViewer.tsx, index.ts)
- 3.Install react-pdf@^9.1.1 using your package manager (pnpm add, npm install, or yarn add)
- 4.Add optimizeDeps.exclude: ['pdfjs-dist'] to vite.config.ts to prevent worker breakage
- 5.Import CogniteFileViewer from './cognite-file-viewer' and render with source prop, client (from useDune().sdk), and explicit height via style or className
Use cases
- Preview PDF documents with page navigation and zoom controls in a Flows dashboard
- Display images with rotation and pan capabilities alongside other app content
- Render text files (CSV, JSON, TXT) as preformatted content in file browsers
- Show Office documents (Word, Excel, PowerPoint) converted to PDF via CDF Document Preview API
- Navigate between linked files via diagram annotations on PDFs
- Flows app developers building file preview features
- Teams managing document-heavy CDF datasets
- Applications requiring multi-format file viewing (PDF, image, text, Office)
integrate-file-viewer FAQ
PDFs (with page navigation, zoom, pan, annotations), Office documents (Word, PowerPoint, Excel, ODS, ODP, ODT, RTF, TSV converted to PDF), images (JPEG, PNG, WebP, SVG, TIFF with zoom, pan, rotation), text files (TXT, CSV, JSON as preformatted), and a fallback renderUnsupported for other types.
No. This skill handles all setup. The PDF.js worker is configured inside CogniteFileViewer.tsx. Just install react-pdf@^9.1.1 and add the Vite optimizeDeps.exclude config. pnpm users may need to add pdfjs-dist as a direct dependency or configure public-hoist-pattern.
Use instanceId source type (requires space and externalId from file.instanceId). This is the only source type that enables the annotation overlay. For files without instanceId, fall back to internalId source type.
Manually reset page, zoom, and rotation state when the source changes, as the component does not reset these automatically. Set page to 1, zoom to 1, and rotation to 0 when navigating to a new file.
The component requires an explicit height. Always set height via the style prop, className, or parent container. Without defined height, the viewer will collapse if the parent has no explicit height constraint.
Full instructions (SKILL.md)
Source of truth, from cognitedata/builder-skills.
name: integrate-file-viewer description: "MUST be used whenever integrating CogniteFileViewer into a Flows app to preview CDF files (PDFs, images, text). Do NOT manually wire up react-pdf or file resolution — this skill handles installation, Vite config, worker setup, and component usage. Triggers: file viewer, file preview, CogniteFileViewer, PDF viewer, view CDF files, document viewer, preview file." allowed-tools: Read, Glob, Grep, Edit, Write, Bash
Integrate CogniteFileViewer
Add CogniteFileViewer to this Flows app to preview CDF files (PDF, image, text).
Dependencies
The file-viewer library files (copied in Step 2) require this npm package:
| Package | Version |
|---|---|
react-pdf | ^9.1.1 |
pdfjs-dist ships as a dependency of react-pdf at the correct version — do not install it separately.
react and @cognite/sdk are assumed to already be present in Flows apps.
Your job
Complete these steps in order. Read each file before modifying it.
Step 1 — Understand the app
Read these files before touching anything:
package.json— detect package manager (packageManagerfield or lock file) and existing depsvite.config.ts— understand current Vite setup- The component where the viewer should be added
Step 2 — Copy the file-viewer source files
The file-viewer library lives in the code/ directory next to this skill file. Read and copy
all files from there into src/cognite-file-viewer/ inside the app:
code/types.tscode/mimeTypes.tscode/fileResolution.tscode/useViewport.tscode/useFileResolver.tscode/useDocumentAnnotations.tscode/DocumentAnnotationOverlay.tsxcode/CogniteFileViewer.tsxcode/index.ts
The PDF.js worker is configured inside
CogniteFileViewer.tsx— no separate consumer setup is needed.
Step 3 — Install dependencies
Install react-pdf (see Dependencies above) using the app's package manager:
- pnpm →
pnpm add react-pdf@^9.1.1 - npm →
npm install react-pdf@^9.1.1 - yarn →
yarn add react-pdf@^9.1.1
pnpm users: pnpm's strict linking may prevent the browser from resolving
pdfjs-dist. Either addpdfjs-distas a direct dependency (pnpm add pdfjs-dist), or addpublic-hoist-pattern[]=pdfjs-distto.npmrc.
Step 4 — Configure Vite
Add optimizeDeps.exclude: ['pdfjs-dist'] to vite.config.ts to prevent Vite from pre-bundling pdfjs-dist (which breaks the worker):
export default defineConfig({
// ... existing config ...
optimizeDeps: {
exclude: ['pdfjs-dist'],
},
});
Step 5 — Use the component
Import and render CogniteFileViewer from the locally copied files:
import { CogniteFileViewer } from './cognite-file-viewer';
Get the sdk from the useDune() hook (already available in every Flows app):
import { useDune } from '@cognite/dune';
const { sdk } = useDune();
Supported file types
| Type | Formats |
|---|---|
.pdf — page navigation, zoom, pan, diagram annotation overlay | |
| Office documents | Word, PowerPoint, Excel, ODS, ODP, ODT, RTF, TSV — converted to PDF via the CDF Document Preview API, then rendered identically to PDF |
| Image | JPEG, PNG, WebP, SVG, TIFF — zoom, pan, rotation |
| Text | .txt, .csv, .json — rendered as preformatted text |
| Other | Falls back to renderUnsupported |
Minimal usage
This is all you need — zoom, pan, and touch gestures are handled internally:
<CogniteFileViewer
source={{ type: 'internalId', id: file.id }}
client={sdk}
style={{ width: '100%', height: '600px' }}
/>
The component needs a defined height. If the parent has no explicit height, the viewer will collapse to zero. Always set a
heightviastyle,className, or the parent container.
File source
Pass any of three source types:
// By instance ID (data-modelled file — enables annotations)
<CogniteFileViewer
source={{ type: 'instanceId', space: 'my-space', externalId: 'my-file' }}
client={sdk}
/>
// By CDF internal ID
<CogniteFileViewer
source={{ type: 'internalId', id: 12345 }}
client={sdk}
/>
// By direct URL
<CogniteFileViewer
source={{ type: 'url', url: 'https://...', mimeType: 'application/pdf' }}
/>
Prefer instanceId when available — it's the only source type that enables the diagram annotation overlay. When listing files via sdk.files.list(), check file.instanceId first:
source={
file.instanceId
? { type: 'instanceId', space: file.instanceId.space, externalId: file.instanceId.externalId }
: { type: 'internalId', id: file.id }
}
Full props reference
<CogniteFileViewer
// Required
source={source}
client={sdk} // required for instanceId and internalId sources
// PDF pagination
page={page} // controlled current page (1-indexed)
onPageChange={setPage}
onDocumentLoad={({ numPages }) => setNumPages(numPages)}
// Zoom & pan (works on PDF and images)
zoom={zoom} // 1 = 100%; Ctrl/Cmd+wheel, pinch-to-zoom, and middle-click drag built in
onZoomChange={setZoom}
minZoom={0.25} // default
maxZoom={5} // default
panOffset={pan} // controlled pan offset; resets on page change
onPanChange={setPan}
// Fit mode
fitMode="width" // 'width' fits to container width; 'page' fits entire page in container
// Rotation (PDFs and images)
rotation={rotation} // 0 | 90 | 180 | 270
// Diagram annotations (instanceId sources only)
showAnnotations={true} // default
onAnnotationClick={(annotation) => { /* annotation.linkedResource has space + externalId */ }}
onAnnotationHover={(annotation) => {}}
// Custom annotation tooltip (replaces native <title> tooltip)
renderAnnotationTooltip={(annotation, rect) => (
<div style={{
position: 'absolute',
left: rect.x + rect.width,
top: rect.y,
zIndex: 11,
}}>
{annotation.text}
</div>
)}
// Custom overlay (SVG paths, highlights, drawings — works on PDF and images)
renderOverlay={({ width, height, originalWidth, originalHeight, pageNumber, rotation }) => (
<svg
width={width}
height={height}
viewBox={`0 0 ${originalWidth} ${originalHeight}`}
preserveAspectRatio="none"
style={{ position: 'absolute', top: 0, left: 0, pointerEvents: 'all' }}
>
<path d="..." stroke="cyan" fill="none" />
</svg>
)}
// Custom renderers (all optional)
renderLoading={() => <MySpinner />}
renderError={(error) => <MyError message={error.message} />}
renderUnsupported={(mimeType) => <div>Cannot preview {mimeType}</div>}
// Layout
className="..."
style={{ width: '100%', height: '100%' }}
/>
Tips & tricks
Reset page, zoom and rotation when the source changes. The component does not reset these automatically when you switch files — do it yourself:
const navigateToFile = (file: FileInfo) => {
setSelectedFile(file);
setPage(1);
setZoom(1);
setRotation(0);
};
Gate pagination UI on numPages > 0.
onDocumentLoad only fires for PDFs. Don't render pagination controls until you know there are pages to paginate:
{numPages > 0 && (
<>
<button disabled={page <= 1} onClick={() => setPage(p => p - 1)}>‹</button>
<span>{page} / {numPages}</span>
<button disabled={page >= numPages} onClick={() => setPage(p => p + 1)}>›</button>
</>
)}
Annotation click → navigate to linked file.
annotation.linkedResource contains the space and externalId of the linked CDF instance. Match it against file.instanceId to navigate:
onAnnotationClick={(annotation) => {
if (!annotation.linkedResource) return;
const { space, externalId } = annotation.linkedResource;
const linked = files.find(
f => f.instanceId?.space === space && f.instanceId?.externalId === externalId
);
if (linked) navigateToFile(linked);
}}
Touch support is built in. Two-finger pinch-to-zoom and two-finger drag-to-pan work on touch devices automatically. No configuration needed.
Pan is middle-click drag (when zoomed in) on desktop. Left-click remains free for annotation clicks and text selection.
Ctrl/Cmd + wheel zooms toward the cursor — also built in. Wire zoom/onZoomChange if you want programmatic zoom buttons or to persist zoom state; otherwise it works fully uncontrolled.
renderOverlay receives original page dimensions (originalWidth, originalHeight) so you can set up an SVG viewBox in the original coordinate space. Paths drawn in PDF-point or image-pixel coordinates will map correctly to the rendered page at any zoom level.
Common pitfalls
| Problem | Cause | Fix |
|---|---|---|
Failed to resolve module specifier 'pdf.worker.mjs' | pdfjs-dist not hoisted (pnpm) | Add public-hoist-pattern[]=pdfjs-dist to .npmrc, or pnpm add pdfjs-dist directly |
API version does not match Worker version | pdfjs-dist version mismatch between app and react-pdf | Do not install pdfjs-dist separately — let react-pdf provide it. If already installed, remove it |
| Annotations never show | instanceId is undefined — annotation overlay is disabled without it | Use instanceId source, or fall back and accept no annotations for classic files |
| Annotations show but are empty | File has no CogniteDiagramAnnotation edges in CDF | Expected — only P&ID/diagram files synced to the data model have annotations |
| Viewer collapses to zero height | Parent has no explicit height | Set height via style, className, or parent CSS |
Related skills
More from cognitedata/builder-skills and the wider catalog.

integrate-fusion-agent
Integrate your Flows/Dune app with Fusion's built-in PAIA agent panel using @cognite/app-sdk.

integrate-todo-list
Add structured task tracking to Flows apps with Atlas chat integration.

migrate-app-to-flows
Orchestrate full migration of legacy Dune apps to Flows app hosting infrastructure.

performance
Find and fix performance issues in Flows apps—re-renders, inefficient queries, pagination, and memory leaks.

pull-changes-resolve-conflicts
Safely integrate branch changes by analyzing conflicts before resolving, preserving intentional work.

reveal-3d
Embed interactive Cognite Reveal 3D CAD viewer in Flows apps with local bundled source.