Skip to content

Print

Print an invoice, a ticket or any HTML or PDF, or turn HTML into a PDF file you can share. @symbiote-native/print wraps expo-print (AirPrint on iOS, the print framework on Android) so every SymbioteNative adapter can reach it, not just React. Like mail composer, every export is a free function with no per-instance state, so the React, Vue, Angular, Svelte, and Solid entry points are plain re-exports of the same core.

OS platform Support
iOS live
Android live
Framework adapter Support
React live
Vue live
Angular live
Svelte live
Solid live
Terminal window
npm install @symbiote-native/print

Scaffolding or extending a SymbioteNative app? npx @symbiote-native/cli new --print (or add --print in an existing app) installs and wires this for you - see @symbiote-native/cli.

expo-print and expo-modules-core come along as regular dependencies, pinned to exact versions. Never install either yourself, and never add the expo meta-package to your project (it bundles its own Metro/Babel pipeline, which conflicts with this project’s own).

No runtime permission, manifest edit or Info.plist key is needed: the AirPrint sheet and Android’s print framework are system UI the user drives directly.

All five adapters re-export the same functions; there is no per-adapter hook, composable or service, since nothing here holds live state.

import { printAsync } from '@symbiote-native/print/react';
export default function PrintInvoice() {
return (
<button
title="Print"
onPress={() => printAsync({ html: '<h1>Invoice #1234</h1>' })}
/>
);
}
import { printToFileAsync } from '@symbiote-native/print';
const { uri, numberOfPages } = await printToFileAsync({ html: '<h1>Invoice #1234</h1>' });
// uri is a file in the cache directory; hand it to the sharing package to send it on

Pair it with sharing to let the user save or send the PDF.

import { printAsync, selectPrinterAsync } from '@symbiote-native/print';
const { url } = await selectPrinterAsync();
await printAsync({ html: '<h1>Invoice #1234</h1>', printerUrl: url });
Signature Description
printAsync(options): Promise<void> Opens the print UI for an HTML string or a PDF. Takes exactly one of uri or html. One job at a time
selectPrinterAsync(): Promise<IPrinter> Shows the iOS printer picker and resolves the chosen printer. Throws on Android
printToFileAsync(options?): Promise<IFilePrintResult> Renders HTML to a PDF file in the cache directory
Orientation Constants portrait and landscape for IPrintOptions.orientation
Field Type Description
uri string | undefined A PDF to print: a remote or local URI, or a data:application/pdf;base64, URI
html string | undefined An HTML string to print. Use instead of uri
width number | undefined Page width in pixels. Defaults to 612 (US Letter at 72 PPI). Only with html
height number | undefined Page height in pixels. Defaults to 792 (US Letter at 72 PPI). Only with html
printerUrl string | undefined Printer URL from selectPrinterAsync. iOS only
useMarkupFormatter boolean | undefined Render with the native text formatter instead of a web view. No images. iOS only
markupFormatterIOS string | undefined Deprecated upstream. Stands in for html/uri on iOS and warns on every call
orientation string | undefined Orientation.portrait or Orientation.landscape
margins IPageMargins | undefined Page margins as { top, right, bottom, left }
Type Field Description
IFilePrintOptions html HTML to render
IFilePrintOptions useMarkupFormatter Use the native text formatter instead of a web view
IFilePrintOptions width, height Page size in pixels
IFilePrintOptions margins Page margins as { top, right, bottom, left }
IFilePrintOptions base64 Also return the PDF as a base64 string
IFilePrintOptions textZoom Android only. Text zoom percent. Defaults to 100
IFilePrintResult uri Location of the generated PDF
IFilePrintResult numberOfPages Page count of the generated PDF
IFilePrintResult base64 The PDF as base64, without a data: prefix. Present only when requested
  • One print job at a time. A second printAsync call while one is in flight rejects at once. Upstream keeps the same guard as module-level state.
  • markupFormatterIOS is deprecated. Use useMarkupFormatter instead.
  • Printing can only be verified on a device or simulator. The headless tests fake the native module, so they prove input validation and the in-flight guard, not the print UI.

Images are missing from my printed page or PDF. A local file:// image can fail to render inside the HTML, and an image that appears in a development build can vanish in a release build. Embed the image as a base64 data: URI in the HTML, or use an https:// URL the device can reach.

The PDF has an extra blank page at the end. This is a known upstream quirk of HTML-to-PDF. Keep the content a little shorter than the page, and control margins with an @page { margin: ... } rule in your HTML.

How do I set the page size and margins? Use the width and height options (pixels, default 612 by 792, US Letter at 72 PPI) and the margins option, or an @page rule in the HTML.

How do I save or share the PDF? printToFileAsync resolves a uri. Pass it to the sharing package to let the user save or send it.

Can I choose a printer? On iOS, call selectPrinterAsync() and pass the printerUrl to printAsync. Android uses its own print UI.

Sources: Expo docs: Print, expo/expo#6169 problem with printToFileAsync, expo/expo#7435 HTML to PDF adds an extra blank page, expo/expo#24011 image uri path differs between dev and deployed versions.

expo-print’s JS is hand-ported into this package’s core/, resolving ExpoPrint through expo-modules-core rather than the expo meta-package. Upstream ships no config plugin, so the whole native-link.json is the one Android module entry. The five adapter entry points are plain re-exports of core (Angular stays a physical subpath for its separate ngc/AOT build). The native code is never vendored: expo-modules-autolinking resolves it from node_modules (see the native setup guide).