embedpdf
Embed PDF files in Quarto HTML documents — including on mobile
The embedpdf extension adds a shortcode for embedding PDF files in your Quarto HTML documents and RevealJS presentations. On desktop it uses the browser’s built-in PDF viewer; on mobile — where embedded PDFs normally fail to render — it automatically falls back to PDF.js so your readers see the document either way. This guide walks through the available options.
Simple Usage
All you really need to give the pdf shortcode is the path to the PDF file you want to embed.
{{< pdf sample.pdf >}}
Remember to list the PDF file under resources in your document’s YAML header (or under project: resources: in _quarto.yml) so that Quarto copies it into your output site alongside the HTML.
Customization
In most cases you will want to customize the appearance of the embedded PDF. A few common options are built into the shortcode for convenience; for anything more, pass a CSS class and style it yourself.
Embed with width in pixels
{{< pdf sample.pdf width=600 >}}
Embed with width in percent
{{< pdf sample.pdf width=100% >}}
Embed with height in pixels
{{< pdf sample.pdf height=600 >}}
Embed with both width and height
{{< pdf sample.pdf width=600 height=400 >}}
Embed with a 1px border
{{< pdf sample.pdf border=1 >}}
Embed with a CSS class
{{< pdf sample.pdf class=myclass >}}
Supporting Mobile Browsers
Mobile browsers (e.g., Chrome and Firefox on Android) do not support the inline rendering of PDF objects: they show a blank box or a download prompt instead. To solve this, the extension includes a JavaScript-based PDF renderer, PDF.js.
By default (renderer=auto), each embedded PDF checks whether the browser can display PDFs inline (via navigator.pdfViewerEnabled). If it can, the browser’s native PDF viewer is used. If it cannot, as on Android, PDF.js draws the PDF page by page. The PDF.js viewer has a small toolbar for zooming, page tracking, and downloading. iPhone and iPad are the exception to the pdfViewerEnabled check. Safari there reports that it can display PDFs, but users report that older iOS versions show only the first page. For this reason, renderer=auto always uses PDF.js on iPhone and iPad. A browser fetches the PDF.js library only for a PDF.js embed. Desktop visitors with a built-in PDF viewer fetch it only for renderer=pdfjs embeds.
Force the PDF.js renderer
Set renderer=pdfjs to always use PDF.js.
{{< pdf sample.pdf renderer=pdfjs height=500 >}}
Forcing renderer=pdfjs on your desktop is the easiest way to preview exactly what your mobile visitors will see, without needing a phone.
Force the native renderer
Set renderer=native to always use the browser’s built-in viewer.
{{< pdf sample.pdf renderer=native height=400 >}}
In Safari on iPhone and iPad, renderer=native shows the PDF in Safari’s own viewer. This was checked on 2026-10-18 in iOS 27.0 iPhone and iPad simulators and an iOS 27.1 iPhone simulator. In the iOS 27.1 iPhone simulator, a swipe inside the embed reached every page.
Self-contained documents (embed-resources: true) need no other file. The PDF and, for auto and pdfjs embeds, PDF.js are inside the one HTML file. See selfcontained_test.html for a self-contained page. The README “Known limitations” section lists where this was checked and what happens with JavaScript disabled.
Hide the PDF.js toolbar
{{< pdf sample.pdf renderer=pdfjs toolbar=false height=400 >}}
Setting defaults for the whole document or project
You can set default values for any shortcode option under the embedpdf key in your document YAML header or _quarto.yml, so you don’t have to repeat them:
embedpdf:
renderer: pdfjs
height: 600PDFs on Another Site
You can give the shortcode the URL of a PDF on another site:
{{< pdf https://example.com/report.pdf >}}
This section is about pages that are not self-contained. On desktop, renderer=auto uses the browser’s built-in viewer, so this section is about PDF.js embeds. renderer=auto uses PDF.js on iPhone and iPad and in browsers with no built-in PDF viewer, such as Chrome on Android. renderer=pdfjs uses PDF.js everywhere.
With PDF.js, your page reads the PDF itself. To let your page read a PDF from another site, the browser needs that site to allow the read with an Access-Control-Allow-Origin header. The checks named at the end of this section used only the value *.
Without the header, the embed shows “This PDF cannot be shown here.” and an “Open the PDF” link. The link opens the PDF in a new tab.
On 2026-10-18, curl -I showed access-control-allow-origin: * for https://jmgirard.github.io/embedpdf/sample.pdf, a file on GitHub Pages. On the same date, https://nbviewer.org/github/jhelvy/cv/blob/main/cv-jph.pdf sent no such header.
To avoid the problem, put the PDF in your Quarto project and list it under resources in the YAML header. Then give the shortcode its relative path, for example {{< pdf cv.pdf >}}. If a script makes the PDF somewhere else, copy it into the project before you render.
In Safari, a PDF.js embed of a PDF from another site can fail even with the header. The cause is an embed with renderer=native on the same page that shows the same PDF. This was seen once, on 2026-10-18, in an iOS 27.0 iPhone simulator.
These cases were checked on 2026-10-18 in Chromium with an emulated iPhone and an emulated Android phone. Android was checked by emulation in Chromium, not on a device. iPhone and iPad were checked only in Safari in iOS 27.0 simulators, with a site that sends no header.
When JavaScript is Disabled
The viewer requires JavaScript to run. If a visitor has JavaScript disabled, the embedded PDF is replaced by a simple hyperlink to download the file. Adding a download button (button="...") gives those visitors a clearer call to action.