Skip to main content

Create a Bundle Document from HTML

Generate a PDF from HTML and send it for electronic signature in a single Blueink API call — no need to render the PDF yourself, host it, or upload it as a file. Provide HTML (with optional CSS for layout and data-blu-* annotations for signature, initial, date, and form fields), and Blueink converts the HTML to a PDF and detects the fields automatically.

This is useful for dynamically generating signable documents from templates, building HTML forms that map directly to e-signature fields, and any workflow where the source-of-truth document lives in HTML rather than as a pre-rendered PDF.

This guide describes how to create a Bundle Document from HTML and documents the rules Blueink uses to convert your HTML to a PDF and extract form fields.

Basic Usage

When creating a new Bundle in Blueink via the Create Bundle endpoint (POST /api/v2/bundles/), you can create a document from HTML by including a file_html parameter on any document. The value should be the escaped HTML of your document.

Field Detection Mode

The optional html_fields_mode parameter on the document object controls how form fields are extracted from the HTML:

  • "blueink" (default) — Detects form elements and data-blu-* annotations and converts them to Blueink fields, as described in this guide.
  • "none" — Skip field detection entirely. The HTML is rendered to a PDF and attached to the document, but no fields are created. Use this when you intend to add fields via the API (e.g., via fields in the Create Bundle request) or via Auto Placement.

1. HTML Structure Requirements

Page Size & Layout

Important

Do NOT combine @page { margin } with .page { padding } — this causes double pages!

Option A: Zero page margin (Recommended)

@page {
size: A4;
margin: 0; /* No page margin - padding is handled by .page */
}

.page {
width: 210mm;
min-height: 297mm;
padding: 20mm; /* Content padding inside the page */
margin: 0 auto;
box-sizing: border-box; /* Include padding in dimensions */
}

.page:not(:last-child) {
page-break-after: always;
}

Option B: Page margin with adjusted height

@page {
size: A4;
margin: 20mm; /* 20mm margin on all sides */
}

.page {
width: 170mm; /* 210mm - 40mm (left + right margin) */
min-height: 257mm; /* 297mm - 40mm (top + bottom margin) */
padding: 0; /* No padding - margin handles spacing */
margin: 0 auto;
}

.page:not(:last-child) {
page-break-after: always;
}

Common Mistake: Double Pages

If your 5-page HTML produces 10 PDF pages, check for this issue:

/* ❌ WRONG - causes double pages */
@page { margin: 20mm; }
.page { min-height: 297mm; padding: 20mm; }

/* ✅ CORRECT - use one or the other */
@page { margin: 0; }
.page { min-height: 297mm; padding: 20mm; box-sizing: border-box; }
@media print {
body {
padding: 0;
margin: 0;
background: #FFFFFF;
}
.page {
margin: 0;
width: 100%;
min-height: auto;
box-shadow: none;
}
}

2. Form Field Detection

Field Detection from HTML Form Elements

ElementBlueink FieldDefault ValidationExample
<input type="text">TextNone<input type="text" name="first_name">
<input type="email">TextValid Email<input type="email" name="email">
<input type="tel">TextValid Phone<input type="tel" name="phone">
<input type="number">TextNumbers Only<input type="number" name="age">
<input type="url">TextNone<input type="url" name="website">
<input type="search">TextNone<input type="search" name="q">
<input type="password">TextNone<input type="password" name="pwd">
<input type="checkbox">CheckboxNone<input type="checkbox" name="agree">
<input type="radio">Checkbox Group (cbg)None<input type="radio" name="option" value="a">
<textarea>Multiline TextNone<textarea name="notes"></textarea>
<select>DropdownNone<select name="country"><option>...</option></select>

For Date fields (dat) and Signing Date / Timestamp fields (tms), use data-blu-field-kind on any element. See Field Kind below.

Radio buttons that share the same name attribute are automatically grouped into a single Checkbox Group field (kind cbg), with the group key derived from the shared name.

A <select> element with no <option> children is silently skipped.

To ignore a form element in the HTML, add a data-blu-ignore attribute with any non-empty value.

<input type="text" data-blu-ignore="1" />

Unsupported Elements (Skipped)

These input types are skipped during field detection:

  • <input type="button">
  • <input type="submit">
  • <input type="reset">
  • <input type="image">
  • <input type="date"> — use data-blu-field-kind="dat" on any element to create a Date field instead

Signature, Initial and Signing Date Fields

Signature, Initial and Signing Date fields are detected by CSS class or by including a data-blu-field-kind attribute. When both are present on the same element, data-blu-field-kind takes precedence; the CSS classes are a convenience/legacy path used when data-blu-field-kind is absent.

<!-- Any of these classes / attributes will be detected as a Signature field -->
<div class="blu-signature-field"></div>
<div class="blu-signature"></div>
<div class="blu-sign"></div>
<div data-blu-field-kind="sig"></div>

<!-- Any of these classes / attributes will be detected as an Initials field -->
<div class="blu-initial-field"></div>
<div class="blu-initial"></div>
<div data-blu-field-kind="ini"></div>

<!-- Any of these classes / attributes will be detected as a Signing Date field -->
<div class="blu-signing-date"></div>
<div data-blu-field-kind="tms"></div>

3. Specifying Other Field Attributes

You can set additional field parameters by adding data attributes to an element. All attributes start with data-blu-.

3.a. Field Kind

Use the data-blu-field-kind attribute for explicit field type declaration. The allowed field kinds match the values for kind in the documentation for fields in the Create Bundle request in the API Reference.

KindField Type
sigSignature
iniInitials
tmsSigning Date / Timestamp
datDate
inpSingle-line Text
txtMulti-line Text
selDropdown
chkCheckbox
cbgCheckbox Group
<input type="text" name="first_name" data-blu-field-kind="inp">
<select name="country" data-blu-field-kind="sel">
<input type="checkbox" name="agree" data-blu-field-kind="chk">
<textarea name="notes" data-blu-field-kind="txt"></textarea>
<div class="signature-field" data-blu-field-kind="sig">Sign Here</div>
<div data-blu-field-kind="dat" data-blu-field-format="MM/DD/YYYY"></div>

3.b. Other Field Attributes

  • Label: data-blu-field-label -- the label for the field, shown to signers. Note that if a label is not provided via this attribute, Blueink will attempt to detect the label from the surrounding HTML. See "Detecting Field Labels" below.
  • Format: data-blu-field-format -- a format string for Date (dat) or Signing Timestamp (tms) fields.
  • Required: data-blu-field-required -- set to 1 or true (case-insensitive) to mark the field as required. Any other value -- including yes, on, 0, false, or omitting the attribute -- leaves the field as not required.
  • Initial Value: data-blu-field-value -- the initial value for the field. Alternatively, the value can be set via the value attribute for form fields. The data-blu-field-value attribute takes precedence over the value attribute.
  • Validation Pattern: data-blu-field-v-pattern -- one of the named validation patterns listed in the API Reference.
  • Min Length: data-blu-field-v-min -- the minimum length for the field.
  • Max Length: data-blu-field-v-max -- the maximum length for the field.
  • Group: data-blu-field-group -- the group name for fields that participate in a Checkbox Group (cbg). Multiple checkboxes that share the same group name are combined into a single Checkbox Group field. (For radio buttons, the shared name attribute serves the same purpose automatically.)
  • Editors: data-blu-field-editors -- a comma-separated list of editor names. These are a list of Signer keys, as specified in the documentation for editors in the Create Bundle request in the API Reference. The comma separated list can contain spaces (which are ignored). If no editor names are provided, the field will be read-only.

Detecting Field Labels

If a field label is not provided via data-blu-field-label, Blueink will attempt to detect the label from the surrounding HTML. The label search proceeds as follows. This applies for valid form tags (input, select, textarea) as well as for other tags (e.g. div) identified as fields via data-blu-field-kind.

  1. A <label> tag with a for attribute matching the field's id.
  2. Enclosing <label> tag (if any).
  3. Preceding sibling <label> tag.
  4. The text of the nearest preceding <span>, <div>, or <p> element with a non-empty text shorter than 100 characters.
  5. The field's name attribute, as a final fallback.

To prevent Blueink from detecting a label, add the attribute data-blu-field-label="" to the field element.

Field IDs

Each detected field is assigned an ID derived from the source element. Blueink uses the element's name attribute, falling back to the id attribute, and finally to a generated identifier if neither is present. Characters that are reserved in PDF AcroForm field names -- (, ), <, >, [, ], {, }, /, % -- are replaced with underscores in the generated field key.


4. Field Layout

Blueink inspects the placement and dimensions of the field element in the HTML to determine the placement of the field on the PDF. It is important that the field element occupies the same space in the HTML as it will in the PDF. Technically, the element must generate a CSS box in the layout (i.e., it must participate in the render tree).

In practice, this means the element should have a display property of block, inline-block, flex, or grid. inline can work, but is less reliable as an inline element will collapse to zero width if it has no content.

Specifying a position of absolute or fixed will also work.

These attributes are also acceptable, but can make debugging your HTML more difficult. In both cases, the element will still occupy space in the layout, but will not be visible in the browser.

  • visibility: hidden
  • opacity: 0

5. Best Practices

  1. Use semantic HTML - Proper form elements for better field detection
  2. Set page breaks - Use .page class with page-break-after: always
  3. Avoid double margins - Use either @page { margin } OR .page { padding }, not both
  4. Use box-sizing - Add box-sizing: border-box to include padding in dimensions
  5. Test print styles - Ensure @media print styles work correctly
  6. No JavaScript - All <script> tags and event handlers are removed for security

6. Example HTML Template

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Form Template</title>
<style>
@page {
size: A4;
margin: 0; /* Zero margin - padding handled by .page */
}

body {
margin: 0;
padding: 0;
background: #f5f5f5;
}

.page {
width: 210mm;
min-height: 297mm;
padding: 20mm;
margin: 0 auto;
background: white;
box-sizing: border-box; /* Include padding in dimensions */
}

.page:not(:last-child) {
page-break-after: always;
}

.blu-signature-field {
border: 2px dashed #999;
min-height: 80px;
}

@media print {
body { background: white; }
.page { margin: 0; box-shadow: none; }
}
</style>
</head>
<body>
<div class="page">
<h1>Form Title</h1>
<label>Name:</label>
<input type="text" name="name" data-blu-field-kind="inp">
<label>Signature:</label>
<div class="blu-signature-field"></div>
</div>
</body>
</html>

7. Security

JavaScript Removal

All JavaScript code is automatically removed from HTML files before PDF conversion for security:

RemovedExample
<script> tags<script>alert('xss')</script>
<noscript> tags<noscript>...</noscript>
Event handlersonclick="...", onload="...", onerror="..."
JavaScript URLsjavascript: schemes in href, src, action, formaction, and data attributes

8. HTML Parsing Stability

The HTML-to-PDF and field-detection rules described in this guide are part of the stable Blueink APIv2 surface. Blueink will preserve backwards compatibility for HTML submitted via the file_html parameter on POST /api/v2/bundles/, including the set of recognized data-blu-* attributes, the field-kind values, and the label-detection algorithm.

The underlying HTML parser may evolve over time (for example, to support new field kinds or improve layout fidelity). When such changes are introduced, they will either be additive (no change to behavior for existing HTML) or gated behind an explicit opt-in. A future release is expected to introduce a pipeline parameter that pins the parser to a specific specification version, so that integrators can adopt new parser behavior on their own schedule. Until that parameter is available, the behavior described in this guide is the contract.