Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Html2Pdf Laravel Package

soqrate/html2pdf

soqrate/html2pdf is a Laravel/PHP package for converting HTML and Blade templates into PDF documents. It provides a simple API for generating downloadable or streamable PDFs, with configurable options for page size, orientation, and styling.

View on GitHub
Deep Wiki
Context7

Getting Started

Because soqrate/html2pdf has no meaningful adoption (0 stars, 0 dependents on Packagist) and essentially no community documentation, treat onboarding as a code-reading exercise rather than a tutorial exercise.

Install

composer require soqrate/html2pdf

First place to look

  1. Check composer.json in vendor/soqrate/html2pdf/ to see which engine is actually wrapped (Dompdf, mPDF, TCPDF, or a headless browser). This determines every capability limit you'll hit later.
  2. Open src/ and look for a class named Html2Pdf, HTML2PDF, or similar. There is likely a single facade class with create()/output()/save() methods.
  3. Look for a config/ folder — if none exists, configuration is done through constructor arguments or setters, not through config/html2pdf.php.
  4. Check whether a ServiceProvider exists. If not, instantiate the class directly; there is nothing to auto-resolve.

First use case — a one-off PDF from a Blade view

use Soqrate\Html2Pdf\Html2Pdf; // verify namespace by reading src/

Route::get('/invoice/{id}', function ($id) {
    $html = view('invoices.show', ['invoice' => Invoice::findOrFail($id)])->render();

    $pdf = new Html2Pdf();          // constructor signature varies — read it
    $pdf->writeHTML($html);         // or ->setHtml() / ->loadHtml(), depending on wrapped engine
    $pdf->output('invoice-' . $id . '.pdf'); // or ->save($path), or returns a string
});

Do this once in a throwaway route before writing any abstraction. The exact method names are unknown until you read the source, and guessing wastes more time than five minutes of reading.

Implementation Patterns

Wrap it immediately. Never call the package directly from controllers. The public API surface of an undocumented package is not something you want scattered across your codebase — one method rename in a patch release breaks every call site.

// app/Services/PdfRenderer.php
class PdfRenderer
{
    public function render(string $view, array $data = [], array $options = []): string
    {
        $html = view($view, $data)->render();
        $pdf  = new Html2Pdf($options);   // adjust to the real constructor
        $pdf->writeHTML($html);

        return $pdf->output('', 'S');      // 'S' = return as string (mPDF convention)
    }
}

Bind this in a service provider and inject it. That gives you a single seam to swap in Dompdf or Browsershot if the package turns out to be unmaintained.

Separate HTML from layout concerns. Build your PDF views as standalone Blade files under resources/views/pdf/ with their own inline <style> block — do not @extends your web layout. PDF engines have no notion of a CSS reset, flexbox, or grid, and pulling in Tailwind/Bootstrap output will produce garbage. Print stylesheets should target the print medium explicitly:

<style>
    @page { margin: 20mm; }
    body { font-family: DejaVu Sans, sans-serif; font-size: 11pt; }
    .page-break { page-break-after: always; }
</style>

Generate large documents on a queue. Long PDFs (100+ page reports, image-heavy invoices) will blow past PHP's max_execution_time. Return a placeholder URL immediately, dispatch a job, store the output on disk or S3, and notify the user.

class GenerateReportPdf implements ShouldQueue
{
    public function handle(PdfRenderer $pdf): void
    {
        $bytes = $pdf->render('pdf.report', ['report' => $this->report->id]);
        Storage::disk('s3')->put($this->path(), $bytes);
        $this->report->update(['pdf_path' => $this->path()]);
    }
}

Use streamed responses for small documents so the browser starts receiving the file before the full render completes, and always name the file with a Content-Disposition header:

return response($bytes, 200, [
    'Content-Type'        => 'application/pdf',
    'Content-Disposition' => 'inline; filename="invoice.pdf"',
]);

Integrate with Storage rather than touching the filesystem directly. Most of these wrappers write to a local temp path. If you need to write to S3, render to a string and let Laravel's filesystem abstraction handle the upload — never pass an S3 URL as the output destination.

Gotchas and Tips

The package may be abandoned or a thin vendor fork. Before committing to it, run composer show soqrate/html2pdf and inspect the require block. If it pins an old Dompdf/mPDF version, you inherit every CVE and rendering bug from that engine. The practical mitigation is the PdfRenderer wrapper above — if it becomes a problem, swapping engines is a one-file change.

No service provider, no facade. Do not attempt Html2Pdf::make() in a Blade template. Instantiate the class explicitly, or alias it in config/app.php yourself. If you find yourself writing app(Html2Pdf::class) and it errors with "Target class not instantiable," the package expects constructor arguments that Laravel cannot resolve automatically — register a factory binding in your own AppServiceProvider.

Encoding and non-ASCII characters. French accents (the package description is French, so this is the intended use case) render as ? or boxes unless the engine is using a UTF-8-capable font. If the wrapper defaults to Helvetica or similar, accented characters will fail. Force DejaVu Sans or Liberation Sans, and confirm the wrapped engine has UTF-8 mode enabled. Also set <meta charset="utf-8"> in the HTML — some engines ignore the PHP-side setting.

CSS support is not browser CSS. Assume no flexbox, no grid, no position: sticky, no box-shadow, limited border-radius, and buggy support for anything newer than CSS 2.1. Tables are your layout primitive for anything structured. Test with a real fixture, not a single-line "Hello World" — layout collapse often only shows up with a full-page invoice.

Images need absolute paths or reachable URLs. Relative src attributes resolve against the engine's base path, which is usually the server's working directory, not your public/ folder. Either call a setBasePath()/setBaseUrl() method if one exists, or inline the image as a base64 data URI. Remote images also require allow_url_fopen and are a common source of SSRF issues — disable remote image loading if you render user-supplied HTML anywhere.

Page breaks are unpredictable. page-break-inside: avoid is honoured inconsistently. If a table row splits across pages mid-cell, wrap rows in a <tbody> per logical group — most engines respect that, and it's the only reliable workaround across Dompdf/mPDF/TCPDF.

Debugging silently-blank output. If the PDF generates but is empty, the most common cause is an unclosed HTML tag or a PHP notice echoed into the buffer. Render the HTML to a file first (file_put_contents('/tmp/debug.html', $html)) and open it in a browser — if it looks correct there, the problem is engine-side; if it doesn't, the problem is your Blade view.

Config quirks. There is likely no publishable config. Settings live on the instance via setters (setPageFormat, setFont, setMargins). These are typically not chainable and often must be called before writeHTML. Read the source to confirm ordering — a call made after the HTML is loaded usually has no effect and fails silently.

Extension point: subclass the wrapper. If you need to inject headers/footers, watermarks, or custom fonts, the cleanest path is to extend the package class in app/Pdf/AppHtml2Pdf.php and override the relevant hook, rather than fighting the public API. This also keeps your customisations out of the vendor directory when you eventually upgrade or replace the package.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route