Documentation

Emoji

jasy renders color emoji as real vector layers, in pure TypeScript. It parses the color-font tables (COLR / CPAL) itself and draws every layer - solid fills and gradients alike - straight into the PDF. No headless browser, no CDN round-trip, no bitmap fallback. @react-pdf/renderer, by contrast, only fetches Twemoji PNGs from a CDN; jasy owns the whole path natively.

Just write the emoji

Point the document at an emoji source with emoji, register that font, and emoji in any string render in color - even inside your normal text font.

import { writeFileSync } from "node:fs";
import { Document, Page, Text, renderToBytes } from "@jasy/pdf";

async function build() {
  const doc = Document({ emoji: "NotoColorEmoji" }, [
    Page({ size: "A4", margin: 56 }, [
      Text("Ready to ship ๐Ÿš€๐ŸŽ‰", { size: 24 }),
    ]),
  ]);

  doc.addFont("NotoColorEmoji", "NotoColorEmoji.ttf"); // a COLR/CPAL color font

  writeFileSync("emoji.pdf", await renderToBytes(doc));
}

build();

The text itself stays in your regular font; only the code points that font can't color-render come from the emoji source. Spacing stays correct either way, because measuring and drawing share the same source.

From a CDN instead of a font

Prefer the react-pdf style? Give emoji a url and jasy fetches one image per emoji from it (${url}${codePointHex}.${format}) and embeds it, transparency included. Handy when you don't want to ship a font, though the font source is smaller, offline and sharper.

const doc = Document(
  {
    emoji: {
      url: "https://cdn.jsdelivr.net/gh/jdecked/twemoji@latest/assets/72x72/",
      format: "png",
    },
  },
  [Page([Text("Shipping with Twemoji ๐Ÿ˜„")])],
);

Good to know

  • Real vectors, pure TS. COLR/CPAL v0 (flat layers) and v1 (gradients and transforms) are parsed and drawn as PDF paths and shadings - the full Noto Color Emoji set renders. No browser, no JVM.
  • A color font drawn as vectors isn't embedded as a font program, so it adds no /FontFile weight.
  • Single code points today. One-code-point emoji (~95% of everyday use) are covered; multi-code-point sequences (flags, ZWJ combos, skin-tone modifiers) are deferred.
  • Bitmap color fonts (Apple Color Emoji's sbix, the CBDT Noto build) and CFF-outline color fonts are not parsed yet - use a glyf-outline COLR font like Noto Color Emoji or Twemoji, or the CDN source.
  • Vue and Nuxt too. Pass emoji on the document options exactly as above.
jasypdf

Declarative PDFs in pure TypeScript. ZUGFeRD & XRechnung compliant, with no headless browser and no Java.

Resources

ยฉ 2026 Florian Heuberger ยท MIT License

Built with Nuxt ยท self-hosted fonts ยท no trackers