react-native-bt-thermal-printer
v0.1.1
Published
A lightweight and easy-to-use Bluetooth thermal printer library for React Native Android applications. This package allows you to connect to Bluetooth printers and print text or QR codes with minimal setup.
Maintainers
Readme
react-native-bt-thermal-printer
A React Native library for printing to classic Bluetooth (SPP) thermal printers on Android. Built from the ground up using native Android Bluetooth APIs with full ESC/POS support. Style your receipts from JavaScript — the native layer handles the rest.
Android only. iOS does not support classic Bluetooth SPP. If your printer uses BLE, this library is not compatible.
Features
- 🖨️ Connect to any classic Bluetooth SPP thermal printer
- 📄 Style receipts from JavaScript using a fluent
DocumentBuilderAPI - 📐 Multi-column rows with automatic text wrapping for long content
- 🔠 Text styling — bold, underline, font size, alignment
- ➖ Dividers, spacing, and QR codes
- ⚡ Built with Kotlin coroutines for non-blocking async operations
- 🔌 Works with Expo (custom dev build) and bare React Native
Requirements
| Requirement | Version | | -------------- | ------- | | React Native | 0.71+ | | Android SDK | API 21+ | | Expo (if used) | SDK 49+ |
Expo Go is not supported. You must use a custom development build or bare workflow since this library contains native Android code.
Installation
npm install react-native-bt-thermal-printerExpo (Managed Workflow)
npx expo install expo-dev-client
npx expo run:androidBare React Native
npx react-native run-androidAndroid Setup
1. Add Permissions to AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Android 11 and below -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- Android 12+ -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
</manifest>2. Request Runtime Permissions (Android 12+)
On Android 12 and above, Bluetooth permissions must be requested at runtime:
import { PermissionsAndroid, Platform } from 'react-native';
const requestBluetoothPermissions = async (): Promise<boolean> => {
if (Platform.OS !== 'android') return true;
if (Platform.Version >= 31) {
const results = await PermissionsAndroid.requestMultiple([
PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
]);
return (
results['android.permission.BLUETOOTH_CONNECT'] ===
PermissionsAndroid.RESULTS.GRANTED &&
results['android.permission.BLUETOOTH_SCAN'] ===
PermissionsAndroid.RESULTS.GRANTED
);
}
const result = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION
);
return result === PermissionsAndroid.RESULTS.GRANTED;
};Pairing Your Printer
This library connects to already paired devices only. It does not handle Bluetooth pairing. Before using the library, pair your printer through Android's Bluetooth settings:
Settings → Bluetooth → Pair new device → select your printer
Usage
Basic Example
import {
getPairedDevices,
connect,
disconnect,
printDocument,
DocumentBuilder,
} from 'react-native-bt-thermal-printer';
// 1. Get paired devices
const devices = await getPairedDevices();
console.log(devices);
// [{ name: 'Thermal Printer XP-58', address: '00:11:22:33:44:55' }]
// 2. Connect to printer
await connect(devices[0].address);
// 3. Build and print a document
const doc = new DocumentBuilder(32) // 32 for 58mm, 48 for 80mm
.heading('MY STORE')
.divider()
.row([
{ text: 'Burger', width: 22, align: 'left' },
{ text: '$10.00', width: 10, align: 'right' },
])
.divider()
.newline(3);
await printDocument(doc);
// 4. Disconnect when done
await disconnect();API Reference
getPairedDevices()
Returns a list of Bluetooth devices already paired with the Android device.
getPairedDevices(): Promise<PrinterDevice[]>interface PrinterDevice {
name: string; // e.g. "Thermal Printer XP-58"
address: string; // MAC address e.g. "00:11:22:33:44:55"
}Example:
const devices = await getPairedDevices();
// [{ name: 'XP-58', address: '00:11:22:33:44:55' }]connect(address)
Connects to a paired printer by its MAC address.
connect(address: string): Promise<boolean>Example:
await connect('00:11:22:33:44:55');disconnect()
Disconnects from the currently connected printer.
disconnect(): Promise<boolean>isConnected()
Returns whether a printer is currently connected.
isConnected(): Promise<boolean>printDocument(builder)
Sends a DocumentBuilder document to the connected printer.
printDocument(builder: DocumentBuilder): Promise<boolean>Throws NOT_CONNECTED if no printer is connected.
DocumentBuilder
DocumentBuilder is a fluent API for building styled print documents in JavaScript. Pass the printer width in characters to the constructor — 32 for 58mm printers and 48 for 80mm printers.
const doc = new DocumentBuilder(32);.heading(text)
Prints centered bold large text. Ideal for store names or section headers.
doc.heading('MY STORE');Output:
MY STORE.line(text, style?)
Prints a single line of text with optional styling.
doc.line('Hello World');
doc.line('Bold text', { bold: true });
doc.line('Centered', { align: 'center' });.text(text, style?)
Same as .line() but does not add a newline at the end. Useful for inline content.
doc.text('No newline here', { bold: true });.bold(text)
Shorthand for a bold line.
doc.bold('TOTAL: $25.00');.center(text, style?)
Shorthand for a centered line.
doc.center('Thank you for your order!');.row(columns)
Prints a row of columns side by side. Long text automatically wraps within its column width without affecting adjacent columns.
doc.row(columns: RowColumn[])interface RowColumn {
text: string;
width: number; // number of characters this column occupies
align?: 'left' | 'center' | 'right';
style?: TextStyle;
}Example — receipt line:
doc.row([
{ text: 'Chicken Tikka Masala Special', width: 22, align: 'left' },
{ text: '$12.00', width: 10, align: 'right' },
]);Output:
Chicken Tikka Masala $12.00
SpecialExample — table header:
doc.row([
{ text: 'Item', width: 16, align: 'left' },
{ text: 'Qty', width: 6, align: 'center' },
{ text: 'Price', width: 10, align: 'right' },
]);Column widths must add up to your printer width (32 or 48).
.divider(char?)
Prints a full-width divider line. Defaults to -.
doc.divider(); // --------------------------------
doc.divider('='); // ================================
doc.divider('.'); // .................................newline(count?)
Adds one or more blank lines. Defaults to 1.
doc.newline(); // 1 blank line
doc.newline(3); // 3 blank lines (feed paper before cut).qrCode(data, size?)
Prints a QR code. Size defaults to 6 and ranges from 1 (smallest) to 8 (largest).
doc.qrCode('https://mystore.com/receipt/123');
doc.qrCode('https://mystore.com/receipt/123', 8);Text Style Options
All text methods accept an optional TextStyle object:
interface TextStyle {
bold?: boolean;
underline?: boolean;
align?: 'left' | 'center' | 'right';
fontSize?: 'normal' | 'large' | 'small';
}Examples:
doc.line('Big bold centered', {
bold: true,
align: 'center',
fontSize: 'large',
});
doc.line('Underlined note', { underline: true });
doc.line('Right aligned', { align: 'right' });Full Receipt Example
import {
connect,
getPairedDevices,
printDocument,
DocumentBuilder,
} from 'react-native-bt-thermal-printer';
const printReceipt = async () => {
const devices = await getPairedDevices();
await connect(devices[0].address);
const doc = new DocumentBuilder(32)
.heading('MY STORE')
.center('123 Main Street, Karachi')
.center('Tel: 0300-1234567')
.newline()
.divider()
.row([
{ text: 'Item', width: 16, align: 'left' },
{ text: 'Qty', width: 6, align: 'center' },
{ text: 'Price', width: 10, align: 'right' },
])
.divider()
.row([
{ text: 'Chicken Burger', width: 16, align: 'left' },
{ text: '2', width: 6, align: 'center' },
{ text: '$10.00', width: 10, align: 'right' },
])
.row([
{ text: 'French Fries', width: 16, align: 'left' },
{ text: '1', width: 6, align: 'center' },
{ text: '$3.00', width: 10, align: 'right' },
])
.row([
{ text: 'Soft Drink', width: 16, align: 'left' },
{ text: '2', width: 6, align: 'center' },
{ text: '$4.00', width: 10, align: 'right' },
])
.divider()
.row([
{ text: 'TOTAL', width: 22, align: 'left', style: { bold: true } },
{ text: '$17.00', width: 10, align: 'right', style: { bold: true } },
])
.newline()
.center('Thank you for your order!')
.newline()
.qrCode('https://mystore.com/receipt/001')
.newline(3);
await printDocument(doc);
};Output:
MY STORE
123 Main Street, Karachi
Tel: 0300-1234567
--------------------------------
Item Qty Price
--------------------------------
Chicken Burger 2 $10.00
French Fries 1 $3.00
Soft Drink 2 $4.00
--------------------------------
TOTAL $17.00
Thank you for your order!
[QR CODE]Printer Width Guide
| Printer Paper Size | Constructor Value | Characters Per Line |
| ------------------ | ------------------------- | ------------------- |
| 58mm | new DocumentBuilder(32) | 32 |
| 80mm | new DocumentBuilder(48) | 48 |
If text is being cut off or wrapping unexpectedly, you likely have the wrong width. Most small portable Bluetooth printers are 58mm.
Troubleshooting
Printer not showing in getPairedDevices()
Pair the printer in Android Bluetooth settings first. The library only shows already paired devices.
BLUETOOTH_CONNECT permission error
You must request runtime permissions on Android 12+. See the Android Setup section above.
Connected but nothing prints Try adding a short delay after connecting before sending data:
await connect(address);
await new Promise((resolve) => setTimeout(resolve, 500));
await printDocument(doc);Garbled or unreadable text Your printer may use a different character encoding. Some cheap printers default to GBK instead of UTF-8. This is printer-specific and may require a firmware change.
Text misaligned in rows Make sure your column widths add up exactly to your printer width (32 or 48).
Platform Support
| Platform | Supported | | -------- | --------- | | Android | ✅ | | iOS | ❌ |
iOS does not support classic Bluetooth SPP. Apple restricts SPP to MFi certified accessories only. If you need iOS support, consider a printer that supports AirPrint or BLE.
License
MIT
