The pdf package renders PDF documents with pdf.js inside a Lattice-styled viewer: pages render onto canvases as you scroll, a text layer makes the document selectable and copyable, and the toolbar provides page navigation, zoom, full-text search with match highlighting, and a download action.
config()->set( 'pdf.worker_url',);
PdfViewer::make('manual') ->url('https://raw.githubusercontent.com/lattice-php/lattice/main/workbench/fixtures/sample.pdf') ->filename('sample.pdf') ->maxHeight(480);- cmapUrl:null
- downloadable:true
- filename:"sample.pdf"
- height:720
- initialZoom:null
- maxHeight:480
- searchable:true
- sidebar:true
- standardFontDataUrl:null
- url:"https://raw.githubusercontent.com/lattice-php/lattice/main/workbench/fixtures/sample.pdf"
- wasmUrl:null
- workerUrl:"https://cdn.jsdelivr.net/npm/[email protected]/build/pdf.worker.min.mjs"
The docs are a static site, so this preview uses a version-matched CDN worker and a CORS-enabled
sample file. A Laravel application should omit the worker_url override and use the package’s
built-in worker route described below.
Installation
Section titled “Installation”composer require lattice-php/pdfComposer is the only install. The lattice() Vite plugin discovers the package through Composer
and adds only a small entry to the app bundle: the viewer shell loads from source, and the pdf.js
engine ships as a precompiled renderer — with pdf.js bundled inside it, while React and the
Lattice runtime remain shared with the host app — that loads on demand the first time a page
renders a document, so pages without a PDF never pay for pdf.js. For a
no-build app, run php artisan lattice:assets after installation; it
publishes the same self-contained renderer as a single standalone plugin.
In an app with a build step, import the viewer stylesheet in your application CSS — it themes the toolbar and pages with the Lattice design tokens and positions the transparent text layer over each canvas:
@import "@lattice-php/pdf/css";use Lattice\Pdf\Components\PdfViewer;
PdfViewer::make('manual') ->url(fn () => $product->firstMediaUrl('manuals')) ->filename('manual.pdf') ->height(720);->url() accepts a string or a closure resolved at serialization time —
the natural place to produce a signed or temporary URL on every render instead of storing one.
The browser fetches the document directly from that URL, so it must be reachable from the client
and same-origin or CORS-enabled.
->filename() names the file the download button saves; without it the browser derives a name
from the URL. Individual toolbar sections can be turned off, and the initial zoom is
configurable:
PdfViewer::make('terms') ->url('/documents/terms.pdf') ->searchable(false) ->downloadable(false) ->zoom(1.5);Without an explicit ->zoom() the document fits the viewer’s width and keeps tracking it as the
container resizes; ->fitWidth() restores that behavior explicitly. Zoom values cover 0.25
to 4.0. The viewer virtualizes rendering — only pages near the viewport hold a live canvas — so
long documents stay responsive.
->height() fixes the viewer’s height; ->maxHeight() lets it grow with the document instead and
only caps it — a single A4 page then shows without dead space below, while longer documents scroll
inside the cap:
PdfViewer::make('manual') ->url('/documents/manual.pdf') ->maxHeight(900);Link annotations in the document are interactive: external URI links open in a new tab, and internal links (a table of contents, cross references) scroll their target page into view inside the viewer.
Sidebar
Section titled “Sidebar”The toolbar’s leftmost button opens a sidebar with page thumbnails — click one to jump to its
page. When the document carries embedded file attachments, the sidebar gains an Attachments tab
listing them for download. ->sidebar(false) removes the toggle, which suits compact embeds such
as modals.
Media attachments
Section titled “Media attachments”With lattice-php/media installed, ->media() sources the document straight
from an attachment — the signed URL and the filename resolve freshly on every render:
PdfViewer::make('manual')->media($product->media('manuals')->first());It accepts a media id or model instance. An explicit ->filename() wins over the media’s stored
name.
In a modal
Section titled “In a modal”The “view document” flow of a record table is a server action that ships a modal containing a
viewer — the action already has the row’s media id, so it builds the Modal and opens it in the
same response:
use Lattice\Ui\Components\Modal;use Lattice\Ui\Enums\ModalWidth;
// In the row action's handle():return ActionResult::success()->openModal( Modal::make('invoice-modal') ->title('Invoice') ->width(ModalWidth::Xl) ->schema([ PdfViewer::make('invoice') ->media($invoiceMediaId) ->sidebar(false) ->height(560), ]),);See Modals for the trigger-embedded alternative, when the viewer’s content is already known at render time instead of resolved inside the action.
The worker asset
Section titled “The worker asset”pdf.js parses documents in a Web Worker whose version must match the bundled library exactly. The
package ships the matching worker script and serves it itself; the service provider registers a
GET route (named lattice.pdf.worker) that streams the artifact with immutable cache headers,
and the component puts that URL on the wire. There is nothing to publish or configure for the
default setup.
In config/pdf.php:
return [ 'middleware' => ['web'], 'asset_route' => 'lattice/pdf/worker.js', 'worker_url' => null, 'cmap_url' => null, 'standard_font_data_url' => null, 'wasm_url' => null,];worker_url overrides the package route entirely — point it at your CDN when you serve static
assets from one. middleware and asset_route reshape the built-in route.
Exotic documents
Section titled “Exotic documents”Typical PDFs with embedded fonts render out of the box. Three optional pdf.js asset sets cover the long tail, and each has a config passthrough that flows into the viewer:
cmap_url— CMap tables for CJK documents without embedded fonts.standard_font_data_url— font data for documents relying on the standard 14 PDF fonts.wasm_url— wasm codecs for JPEG 2000 images and ICC color profiles.
The package does not bundle these (they total several megabytes); host the matching directories
from the pdfjs-dist npm package yourself or on a CDN and point the config at them. The versions
must match the pinned pdfjs-dist release in the package.
Bundle Size
Section titled “Bundle Size”The report measures the precompiled pdf plugin. It includes pdf.js but externalizes React and the framework runtime, so it represents the package’s additional JavaScript — loaded only when a page actually renders a document. The worker script (~1.2 MB) loads separately through the asset route with immutable caching.
145.8 KB gzipped · 566.7 KB raw JavaScript
| Dependency | Raw | Gzip | Share |
|---|---|---|---|
| @lattice-php/pdf | 21.5 KB | 8.6 KB | 5.9% |
| pdfjs-dist | 488.2 KB | 135.4 KB | 92.8% |
| Bundler runtime | 57.1 KB | 1.9 KB | 1.3% |
Emitted JavaScript files
| File | Raw | Gzip |
|---|---|---|
plugin.js | 566.7 KB | 145.8 KB |