Load PDF.js and prepare the canvas
Register your own module with a dependency on the chosen asset. Here core provides Joomla.getOptions(); addScriptOptions() passes the data. The HTML document must render Joomla standard scripts sections. The custom .mjs URL starts from the site root through Uri::root(true), because standard Joomla WebAssetItem does not automatically resolve .mjs paths. Update your own asset version when changing the file to refresh its cache. Initial ES modules finish before DOMContentLoaded; the listener waits for it. For code injected after this event, explicitly import() the initializer and await completion.
This renders the first page with device pixel density taken into account. This preview displays a page image; the example does not implement a text layer, search or annotation UI. Multiple instances need unique script-option names, IDs and per-container handling. Adapt loading, rendering and cleanup for an interactive application.
PHP example
<?php
use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;
$document = Factory::getApplication()->getDocument();
$wa = $document->getWebAssetManager();
$document->addScriptOptions('wtpdf-demo', [
'url' => Uri::root(true) . '/images/documents/catalog.pdf',
'canvasId' => 'wtpdf-canvas',
'errorId' => 'wtpdf-error',
'cMapUrl' => Uri::root(true) . '/media/plg_system_wtpdfjs/viewer/modern/web/cmaps/',
'standardFontDataUrl' => Uri::root(true) . '/media/plg_system_wtpdfjs/viewer/modern/web/standard_fonts/',
'wasmUrl' => Uri::root(true) . '/media/plg_system_wtpdfjs/viewer/modern/web/wasm/',
'iccUrl' => Uri::root(true) . '/media/plg_system_wtpdfjs/viewer/modern/web/iccs/',
]);
$wa->registerAndUseScript(
'com_example.pdf-preview',
Uri::root(true) . '/media/com_example/js/pdf-preview.mjs',
['version' => '1.0.0'],
['type' => 'module'],
['core', 'wt-pdf-js']
);
?>
<canvas id="wtpdf-canvas" aria-label="PDF preview"></canvas>
<p id="wtpdf-error" role="status"></p>JavaScript example 2
// media/com_example/js/pdf-preview.mjs
window.addEventListener('DOMContentLoaded', async () => {
const options = Joomla.getOptions('wtpdf-demo');
const canvas = document.getElementById(options.canvasId);
const error = document.getElementById(options.errorId);
if (!canvas) return;
let loadingTask;
try {
loadingTask = globalThis.pdfjsLib.getDocument({
url: options.url,
cMapUrl: options.cMapUrl,
cMapPacked: true,
standardFontDataUrl: options.standardFontDataUrl,
wasmUrl: options.wasmUrl,
iccUrl: options.iccUrl,
});
const pdf = await loadingTask.promise;
const page = await pdf.getPage(1);
const viewport = page.getViewport({ scale: 1.25 });
const ratio = window.devicePixelRatio || 1;
canvas.width = Math.ceil(viewport.width * ratio);
canvas.height = Math.ceil(viewport.height * ratio);
canvas.style.width = viewport.width + 'px';
canvas.style.height = viewport.height + 'px';
await page.render({
canvasContext: canvas.getContext('2d'),
viewport,
transform: ratio === 1 ? null : [ratio, 0, 0, ratio, 0, 0],
}).promise;
} catch (exception) {
if (error) error.textContent = exception.message;
} finally {
if (loadingTask) await loadingTask.destroy();
}
}, { once: true });For older browsers, use the wt-pdf-js-legacy dependency and replace viewer/modern/ resource paths with viewer/legacy/. For CDN use wt-pdf-js-latest; CMaps, fonts, WASM and ICC must match its actual version. The example local resources are for 6.4.299.
PDF.js 6 expects an options object in getDocument({ url: ... }). The initializers preserve the older string call pdfjsLib.getDocument(url), but use an object in new code. PDF loading parameters are separate from viewer JSON profiles.