Zero dependencies Six custom elements One script tag MIT

Finally, a way to hold it all together.

The zero-dependency web component library for people who just need their HTML to act like a simple piece of paper.

<script src="https://cdn.jsdelivr.net/gh/rlnorthcutt/stapler@main/dist/stapler.min.js"></script>

The problem

Browsers weren't built for staples.

Web browsers were built for infinite scrolling. Business reports were built for staples. Between the two lies a graveyard of broken @media print rules and overlapping footers.

Every developer who has shipped a PDF on a deadline

The mechanism

Three reasons it actually works.

01

Hard-clipped precision

We don't guess. If it doesn't fit on the page, it's gone — cleanly, intentionally, with overflow: hidden instead of a prayer. Build documents like an engineer, not a typesetter.

02

AI-native markup

LLMs are exceptional at writing structured content. They are terrible at calculating millimeter margins. Stapler is designed so a model can emit valid, predictable markup without understanding CSS layout.

Get the AI prompt →

03

Zero drama

No NPM. No build step. No 2 GB node_modules folder having an existential crisis in your project root. One <script> tag. Six custom elements. Done.

The whole API

Six elements. That's the library.

No configuration object, no plugin registry. If you can read HTML, you already know how to use it.

<stapled-doc>

The root. Sets page dimensions, measures, builds. The stapler itself.

<s-page>

One page — a fixed-size, hard-clipped container.

<s-page-body>

The content area inside a page. Your padding goes here.

<page-header>

Declared once, stamped into every page. Skippable per page.

<page-footer>

Same deal, at the bottom of the sheet.

<page-number>

Resolves to 3, 3 / 8, or 3 of 8 when stamped.

5-second setup

From zero to page one.

Drop in the script tag and start writing pages. Each <s-page> is a hard-clipped container — the library handles headers, footers, and page numbers automatically.

<stapled-doc page-width="8.5in" page-height="11in" page-gap="2rem">

  <page-header height="36px" skip-first>
    My Report · <page-number format="n of total"></page-number>
  </page-header>

  <page-footer height="24px">
    Confidential
  </page-footer>

  <s-page skip-header skip-footer>
    <!-- Cover page — no header or footer -->
    <s-page-body style="padding: 3rem;">
      <h1>My Report</h1>
    </s-page-body>
  </s-page>

  <s-page>
    <!-- Page 2 — header and footer stamped automatically -->
    <s-page-body style="padding: 2rem;">
      <p>Content here.</p>
    </s-page-body>
  </s-page>

</stapled-doc>

Where it sits

Compared with the usual options.

Stapler isn't trying to replace a PDF pipeline. It removes the need for one when the document is already HTML.

Approach Runs where Setup What you give up
Stapler Browser One script tag You decide what fits on each page
Server-side PDF (wkhtmltopdf, Puppeteer) Node or a binary Runtime, deploy, security review Preview parity, iteration speed
JS layout engines (paged.js and friends) Browser Polyfilled layout, page-break CSS Predictability on complex content
Raw @media print Browser Nothing to install Consistency across browsers and OSes

Who it's for

People with a deadline and a printer.

App developers shipping reports

Invoices, statements, briefs — generated from data your app already has, printed straight from the page the user is looking at.

Anyone piping an LLM into a document

The model writes the words, the library handles the pages. Paste the prompt, get valid markup back.

Teams tired of a PDF service

One file, no runtime, nothing to keep patched. Delete the microservice.

Ready to stop fighting the browser?

Drop it in. Write documents that respect the concept of a page.