React components and integration for thermal printers
npm install @thermal-print/reactbash
pnpm add @thermal-print/react
or
npm install @thermal-print/react
or
yarn add @thermal-print/react
`
🔄 Migrating from @react-pdf/renderer?
If you're currently using @react-pdf/renderer, check out our comprehensive Migration Guide. Most components are drop-in replacements, and migration is usually straightforward!
🎯 Purpose
This package provides React components optimized for thermal printers, along with conversion utilities for both direct thermal printing (ESC/POS) and browser printing (HTML/PDF).
Three conversion paths:
1. React → ESC/POS - Direct thermal printer output via convertToESCPOS()
2. React → PrintNode IR - Intermediate representation via convertToPrintNodes()
3. React → HTML/DOM - Browser rendering via convertToHTML()
🚀 Quick Start
$3
`typescript
import React from "react";
import {
Document,
Page,
View,
Text,
StyleSheet,
convertToESCPOS,
} from "@thermal-print/react";
const styles = StyleSheet.create({
header: {
fontSize: 20,
textAlign: "center",
fontWeight: "bold",
},
row: {
flexDirection: "row",
justifyContent: "space-between",
},
});
function Receipt() {
return (
MY STORE
Coffee
$3.50
Total
$3.50
);
}
// Convert to ESC/POS and print
const buffer = await convertToESCPOS( , {
paperWidth: 48,
cut: "full",
});
await printer.write(buffer);
`
$3
`typescript
import { Preview } from "@thermal-print/react";
function App() {
return (
This is how it will print!
);
}
`
$3
`typescript
import { convertToHTML } from "@thermal-print/react";
import { convertToPDF } from "@thermal-print/pdf";
async function handlePrint() {
// Step 1: Render to DOM
const htmlResult = await convertToHTML(
,
{
containerId: "thermal-receipt",
keepInDOM: true,
}
);
// Step 2: Convert to PDF
const pdfResult = await convertToPDF("thermal-receipt", {
paperSize: "80mm",
scale: 2,
});
// Step 3: Open print dialog
window.open(pdfResult.url);
// Cleanup
htmlResult.cleanup();
pdfResult.cleanup();
}
`
📖 Components
$3
Root wrapper for thermal printer documents.
`typescript
...
`
Props: None
$3
Semantic page wrapper. Thermal printers print continuously, so this is mainly for logical grouping.
`typescript
Content
`
Props:
- style?: ViewStyle - Layout styling
$3
Layout container with flexbox support.
`typescript
// Column layout (default)
Item 1
Item 2
// Row layout (side-by-side)
Left
Right
// With borders
Content
`
Props:
- style?: ViewStyle - Layout styling
- children?: ReactNode - Child elements
Supported styles:
- flexDirection?: 'row' | 'column'
- justifyContent?: 'space-between' | 'center' | 'flex-start' | 'flex-end'
- padding?: number
- paddingTop?: number
- paddingBottom?: number
- margin?: number
- marginTop?: number
- marginBottom?: number
- borderTop?: string - e.g., '1px solid black' or '1px dashed black'
- borderBottom?: string
- width?: string | number - For columns, e.g., '50%' or 24
$3
Text content with styling support.
`typescript
Hello World
`
Props:
- style?: TextStyle - Text styling
- children?: ReactNode - Text content
Supported styles:
- fontSize?: number - Maps to thermal printer character sizes
- fontWeight?: 'bold' | 'normal' | number - Bold emphasis
- textAlign?: 'left' | 'center' | 'right' - Text alignment
Font size mapping:
- 8-12px → 1x1 (normal)
- 13-18px → 1x2 (double height)
- 19-24px → 2x1 (double width)
- 25+px → 2x2 (double both)
$3
Display images on thermal printers (converted to monochrome).
`typescript
src="data:image/png;base64,..."
style={{ textAlign: "center" }}
/>
`
Props:
- src: string - Image source (data URI or URL)
- style?: { textAlign?: 'left' | 'center' | 'right' } - Alignment
Note: Images are automatically:
- Resized to fit paper width
- Converted to grayscale
- Converted to monochrome (1-bit)
- Printed using ESC/POS raster graphics
$3
Visual preview component for development and testing.
`typescript
id="receipt-preview"
paperWidth={48}
showRuler
scale={1.5}
>
Preview content
`
Props:
- id?: string - Container ID (useful for PDF conversion)
- paperWidth?: number - Characters per line (default: 48)
- showRuler?: boolean - Show character ruler at top
- scale?: number - Scale factor (default: 1)
- style?: CSSProperties - Additional CSS styling
$3
Utility for organizing styles (pass-through, no actual processing).
`typescript
const styles = StyleSheet.create({
header: { fontSize: 20, textAlign: 'center' },
text: { fontSize: 12 },
bold: { fontWeight: 'bold' }
});
Title
`
$3
No-op for thermal printers. Reserved for future PDF export compatibility.
`typescript
Font.register({
family: "Roboto",
fonts: [{ src: "https://..." }],
});
`
📖 API Functions
$3
Converts React component directly to ESC/POS buffer. This is a convenience wrapper that combines convertToPrintNodes() + printNodesToESCPOS().
Parameters:
- component: ReactElement - React component to convert
- options?: ConversionOptions - Conversion options
Options:
`typescript
interface ConversionOptions {
paperWidth?: number; // Characters per line (default: 48)
encoding?: string; // Character encoding (default: 'utf-8')
debug?: boolean; // Enable debug output
cut?: boolean | 'full' | 'partial'; // Paper cut (default: 'full')
feedBeforeCut?: number; // Lines to feed before cut (default: 3)
commandAdapter?: 'escpos' | 'escbematech'; // Protocol (default: 'escpos')
adapter?: ComponentMapping | RendererAdapter; // Custom component mapping
}
`
Returns: Promise - ESC/POS command buffer
Example:
`typescript
const buffer = await convertToESCPOS( , {
paperWidth: 48,
cut: 'full',
commandAdapter: 'escpos'
});
`
$3
Converts React component to PrintNode intermediate representation (IR).
Parameters:
- component: ReactElement - React component to convert
- adapter?: RendererAdapter - Optional custom adapter
Returns: PrintNode | null - PrintNode tree
Example:
`typescript
import { convertToPrintNodes } from '@thermal-print/react';
import { printNodesToESCPOS } from '@thermal-print/escpos';
// Step 1: React → PrintNode
const printNode = convertToPrintNodes( );
// Step 2: Manipulate PrintNode if needed
// ... modify printNode ...
// Step 3: PrintNode → ESC/POS
const buffer = await printNodesToESCPOS(printNode, {
paperWidth: 48
});
`
$3
Converts React component to HTML/DOM using ReactDOM. Useful for browser-based workflows.
Parameters:
- component: ReactElement - React component to convert
- options?: ConvertToHTMLOptions - Conversion options
Options:
`typescript
interface ConvertToHTMLOptions {
width?: number; // Container width in pixels (default: 400)
applyThermalStyles?: boolean; // Apply thermal styling (default: true)
format?: 'html' | 'element'; // Return format (default: 'element')
containerId?: string; // Custom container ID
keepInDOM?: boolean; // Keep in DOM (default: false)
}
`
Returns: Promise
`typescript
interface ConvertToHTMLResult {
content: string | HTMLElement; // Rendered content
container: HTMLElement; // Container element
containerId: string; // Container ID
cleanup: () => void; // Cleanup function
}
`
Examples:
Return HTMLElement:
`typescript
const result = await convertToHTML( , {
format: 'element'
});
const element = result.content as HTMLElement;
result.cleanup();
`
Return HTML string:
`typescript
const result = await convertToHTML( , {
format: 'html'
});
const html = result.content as string;
`
Keep in DOM with custom ID:
`typescript
const result = await convertToHTML( , {
containerId: 'my-receipt',
keepInDOM: true,
width: 600
});
// Container stays in DOM, accessible via document.getElementById('my-receipt')
`
🎨 Styling Guide
$3
`typescript
Centered
Left aligned
Right aligned
`
$3
`typescript
Normal (1x1)
Tall (1x2)
Wide (2x1)
Large (2x2)
`
$3
`typescript
Bold text
Also bold
`
$3
`typescript
`
$3
`typescript
Content with margin
Content with padding
`
$3
`typescript
// Two-column layout
Item
$10.00
// Three-column layout with fixed widths
Product
Qty
Price
`
🔧 Advanced Usage
$3
`typescript
import { createAdapter, convertToESCPOS } from '@thermal-print/react';
const customAdapter = createAdapter({
Receipt: 'document',
ReceiptItem: 'text',
Logo: 'image'
});
const buffer = await convertToESCPOS( , {
adapter: customAdapter
});
`
$3
`typescript
import { convertToPrintNodes } from '@thermal-print/react';
import { printNodesToESCPOS } from '@thermal-print/escpos';
let printNode = convertToPrintNodes( );
// Add watermark
printNode = {
...printNode,
children: [
...printNode.children,
{
type: 'text',
props: { children: 'COPY - NOT ORIGINAL' },
children: [],
style: { textAlign: 'center' }
}
]
};
const buffer = await printNodesToESCPOS(printNode);
``