Problem/Motivation
The existing Google Viewer display type routes all PDFs through docs.google.com/viewer. This is unreliable in practice:
- Google throttles or refuses requests for large files, frequently updated files, or sites with high traffic
- PDFs hosted on private or authenticated file systems cannot be passed to Google's external service
- It introduces an unnecessary third-party dependency for a task modern browsers handle natively
- Users on restricted networks (corporate firewalls, government environments) may be blocked from docs.google.com entirely
Modern browsers — Chrome 90+, Firefox 87+, Edge 90+, Safari 16.4+ — all include a native PDF renderer accessible via
. No plugin, no external service, no JavaScript required to trigger it.
The existing Direct Embed option also uses but has no graceful fallback when native rendering is unavailable (e.g. older Android browsers, or Chrome with "Download PDFs" enabled in settings).
Proposed resolution
Add a new display method: "Direct Embed (Google Viewer fallback)" (machine key: native).
This renderer:
- Uses for browsers with native PDF support — detected client-side via the standardised navigator.pdfViewerEnabled API (Chrome 90+, Firefox 87+, Edge 90+,
- Safari 16.4+).
- Falls back to the Google Docs Viewer for browsers that cannot render PDFs natively.
- Shows a visible "PDF not displaying?" hint — with a reload button and download link — only when the Google Docs fallback is active.
- Respects the existing embed_view_fit and embed_hide_toolbar formatter settings (appended as PDF open-parameter fragments to the URL).
- Uses data-pdf-url / data-pdf-viewer-url data attributes instead of directly populating / in HTML, so raw file URLs are not present in the page source at load time (reduces search engine crawlability of the underlying file path).
- Optional integration with media_entity_download: When the field is attached to a Media entity and the media_entity_download module is enabled, the source uses /media/{id}/download?inline=1 instead of the raw file URI. This keeps the file system path out of the HTML entirely, and access control is enforced by Drupal rather than relying on security-by-obscurity.
- Displays accessible title attributes on both and using the Media entity label (when available) or filename as a fallback — no hard dependency on the Media module.
All existing display types are unchanged. The native option is a non-breaking addition.
Changes
Modified files:
- pdf_reader.module — registers pdf_reader_native theme hook with variables: service, file_url, viewer_url, file_name, width, height, download_link, top, bottom
- pdf_reader.libraries.yml — adds native library (depends on core/drupal and core/once, no jQuery)
- src/Plugin/Field/FieldFormatter/FieldPdfReaderField.php — adds native option to getPdfDisplayOptions() and corresponding case 'native': in viewElements()
New files:
Browser support
- │ Browser │ navigator.pdfViewerEnabled │ Result │
- │ Chrome 90+ │ true │ Native │
- │ Firefox 87+ │ true │ Native │
- │ Edge 90+ │ true │ Native │
- │ Safari 16.4+ │ true │ Native │
- │ Chrome (Download PDFs enabled) │ false │ Google Docs │
- │ Older Android browsers │ false or undefined │ Google Docs │
Steps to test
- Apply the patch and run drush cr
- Edit a file field display → confirm "Direct Embed (Google Viewer fallback)" appears in the Renderer dropdown
- Set renderer to "Direct Embed (Google Viewer fallback)", save, view a node with a PDF file attached
- In Chrome/Firefox/Safari: inspect DOM — confirm has its data attribute set by JavaScript (not present in page source)
- Confirm no request to docs.google.com in the Network tab
- Simulate fallback: in Chrome, go to Settings → Privacy and security → Site settings → PDF documents → enable "Download PDFs". Reload — the Google Docs should load and the "PDF not displaying?" hint should appear.
- Run vendor/bin/phpunit web/modules/contrib/pdf_reader/tests/ --group pdf_reader
AI assisted planning and coding
- Claude.ai and Claude code assisted in the planning and creation of this code
- Manual verification of code and testing of features and fallbacks scenarios
Comments
Comment #2
penyaskitoThis is clearly AI generated without human review. AI disclosure is mandatory on d.org, or could end with a ban on your account.
Please create an MR (not a patch).
Comment #3
whthat commentedComment #6
whthat commentedThis code was certainly written with the help of AI, no intention of hiding that. Glad you mentioned it and fully support good reviews over supporting hallucinations.
Updated the description to include that and created a proper Merge Request, also added the standard .gitlab-ci.yml for testing pipelines. Anything that would be helpful as far as disclosure or code verification please let me know.
Some of this functionality could be applied to existing Field Formatters. Let me know if you would like me to include or provide separate Issue/PRs for them? Could include:
<object>and<Iframe><object>and<Iframe><object>vs Direct filenames