npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-pdf-rtl

v0.1.2

Published

RTL (Hebrew & Arabic) support utilities and components for @react-pdf/renderer

Readme

react-pdf-rtl

RTL (Hebrew & Arabic) support for @react-pdf/renderer

@react-pdf/renderer is a fantastic library — but Hebrew and Arabic text rendering is broken out of the box. Mixed content like "חפירה וביסוס - 3 מ״ק" renders reversed. Currency ₪1,500 gets scrambled. Tables need row-reverse everywhere. Font setup is undocumented.

This library fixes all of that.


Installation

npm install react-pdf-rtl
# peer dependencies
npm install @react-pdf/renderer react

Quick Start

import { Document, Page } from "@react-pdf/renderer";
import {
  setupHebrewPDF,
  RTLText,
  RTLTable,
  RTLSummaryRow,
  RTLDivider,
  getRTLPageStyle,
} from "react-pdf-rtl";

// Register Rubik font + disable hyphenation — call once at module level
setupHebrewPDF();

const pageStyle = getRTLPageStyle("Rubik");

export function QuotePDF({ items, total }) {
  return (
    <Document>
      <Page size="A4" style={pageStyle}>
        <RTLText style={{ fontSize: 20, fontWeight: "bold" }}>
          הצעת מחיר
        </RTLText>

        <RTLDivider marginVertical={12} />

        <RTLTable
          columns={[
            { header: "תיאור עבודה", key: "description", flex: 3 },
            { header: "כמות", key: "quantity", flex: 1, align: "center" },
            { header: "יחידה", key: "unit", flex: 1, align: "center" },
            { header: "מחיר יחידה", key: "unitPrice", flex: 1, isCurrency: true },
            { header: 'סה"כ', key: "total", flex: 1, isCurrency: true },
          ]}
          data={items}
          headerBg="#1F2937"
          headerColor="#EAB308"
        />

        <RTLDivider marginVertical={8} />

        <RTLSummaryRow label='סה"כ לפני מע"מ' value={total} isCurrency />
        <RTLSummaryRow label='מע"מ 18%' value={total * 0.18} isCurrency />
        <RTLSummaryRow
          label="סכום סופי לתשלום"
          value={total * 1.18}
          isCurrency
          bold
        />
      </Page>
    </Document>
  );
}

API Reference

Font Setup

setupHebrewPDF(fontFamily?)

One-shot setup. Registers font + disables hyphenation. Call once at module level.

setupHebrewPDF();           // defaults to "Rubik"
setupHebrewPDF("NotoSansHebrew");

registerRubik()

Registers Rubik (weights 300, 400, 500, 700) from Google Fonts CDN.

registerNotoSansHebrew()

Registers Noto Sans Hebrew from Google Fonts CDN.

registerRTLFont(options)

Register any custom font:

registerRTLFont({
  family: "MyFont",
  fonts: [
    { src: "/fonts/MyFont-Regular.ttf", fontWeight: "normal" },
    { src: "/fonts/MyFont-Bold.ttf", fontWeight: "bold" },
  ],
});

disableHyphenation()

Prevents Hebrew words from being split mid-word. Called automatically by setupHebrewPDF.


Components

<RTLText>

Drop-in replacement for <Text> with automatic RTL detection and bidi wrapping.

<RTLText style={{ fontSize: 14 }}>חפירה וביסוס - 3 מ"ק</RTLText>
<RTLText direction="rtl">כותרת</RTLText>
<RTLText direction="ltr">English text</RTLText>
<RTLText direction="auto">auto-detected</RTLText>  {/* default */}

| Prop | Type | Default | Description | |------|------|---------|-------------| | children | string \| number | — | Text content | | style | Style | — | react-pdf style | | direction | "rtl" \| "ltr" \| "auto" | "auto" | Force or auto-detect direction | | wrap | boolean | true | Allow text wrapping |

<RTLView>

A <View> pre-set with flexDirection: "row-reverse" and textAlign: "right".

<RTLView style={{ gap: 8 }}>
  <RTLText>תיאור</RTLText>
  <Text>₪1,200</Text>
</RTLView>

<RTLTable>

Full RTL-aware table. Columns rendered right-to-left. Hebrew cells auto-wrapped.

<RTLTable
  columns={[
    { header: "תיאור", key: "description", flex: 3 },
    { header: "כמות", key: "qty", flex: 1, align: "center" },
    { header: "מחיר", key: "price", flex: 1, isCurrency: true },
  ]}
  data={rows}
  headerBg="#1F2937"
  headerColor="#FFFFFF"
  stripeBg="#F9FAFB"
/>

| Column Prop | Type | Description | |------------|------|-------------| | header | string | Column header (auto RTL-wrapped) | | key | string | Row data key | | flex | number | Relative width | | width | number | Fixed width in pts | | align | "right" \| "left" \| "center" | Cell text alignment | | isCurrency | boolean | Formats as ₪1,500 | | render | (value, row) => string | Custom cell renderer |

<RTLSummaryRow>

Label + value row for totals, right-aligned label, left-aligned value.

<RTLSummaryRow label='סה"כ' value={12500} isCurrency bold />

<RTLDivider>

Simple horizontal rule.

<RTLDivider color="#E5E7EB" thickness={1} marginVertical={8} />

getRTLPageStyle(fontFamily?)

Returns a base Style object for RTL pages.

const style = getRTLPageStyle("Rubik");
// { fontFamily: "Rubik", direction: "rtl", textAlign: "right", padding: ... }

Utilities

hasRTLChars(str)

Returns true if string contains any Hebrew/Arabic characters.

isRTLDominant(str)

Returns true if the majority of alphabetic characters are RTL.

wrapRTL(str) / wrapLTR(str)

Manually wrap text in Unicode bidi markers (\u202B...\u202C).

smartWrap(str)

Auto-detect direction and wrap accordingly. Pure numbers are left unchanged.

formatCurrencyRTL(amount, symbol?, locale?)

Format a number as currency, ensuring and digits render correctly in RTL context.

formatCurrencyRTL(1500)           // ₪1,500 (correct RTL direction)
formatCurrencyRTL(1500, "$", "en-US") // $1,500

splitBidiSegments(str)

Split mixed text into RTL/LTR/neutral segments:

splitBidiSegments("שלום world 123")
// [
//   { text: "שלום ", direction: "rtl" },
//   { text: "world ", direction: "ltr" },
//   { text: "123", direction: "neutral" },
// ]

Why This Exists

The diegomura/react-pdf issue tracker has RTL/Hebrew bug reports dating back to 2019 (#732, #1571, #3010) with no official fix. This library provides a battle-tested layer on top.


License

MIT