qr-code-styling vs qr-image vs qrcode vs qrcode-generator vs react-qr-code
QR Code Generation Libraries for Web Applications
qr-code-stylingqr-imageqrcodeqrcode-generatorreact-qr-codeSimilar Packages:

QR Code Generation Libraries for Web Applications

qr-code-styling, qr-image, qrcode, qrcode-generator, and react-qr-code are all npm packages designed to generate QR codes in JavaScript environments, but they target different use cases, rendering contexts, and styling capabilities. qrcode-generator is a low-level, pure JavaScript library that outputs raw QR data structures or simple SVG/HTML strings without dependencies. qrcode builds on this foundation and adds support for multiple output formats including PNG, SVG, and terminal display, with both browser and Node.js compatibility. qr-image is a Node.js-only package focused on server-side image generation in PNG, SVG, EPS, and PDF formats. qr-code-styling is a browser-focused library that emphasizes visual customization—allowing gradients, rounded corners, custom logos, and advanced SVG styling. react-qr-code is a lightweight React component wrapper that renders SVG-based QR codes with minimal props and no external dependencies.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
qr-code-styling02,767516 kB110a year agoMIT
qr-image01,062-159 years agoMIT
qrcode08,076135 kB1222 years agoMIT
qrcode-generator02,324556 kB627 months agoMIT
react-qr-code086713.8 kB149 months agoMIT

QR Code Generation in JavaScript: A Practical Comparison

Generating QR codes seems simple at first glance—but the right library depends heavily on your environment (browser vs. Node.js), output format (SVG vs. PNG), and whether you need visual customization. Let’s compare the five most common options by looking at real usage patterns.

🖼️ Rendering Context: Browser, Node.js, or Both?

Not all QR libraries work everywhere. Your runtime dictates your choices.

qr-code-styling only works in the browser—it uses DOM APIs and Canvas/SVG manipulation. You can’t use it in Node.js.

// qr-code-styling: browser-only
import QRCode from "qr-code-styling";

const qrCode = new QRCode({
  width: 300,
  height: 300,
  data: "https://example.com",
  image: "/logo.png"
});
qrCode.append(document.getElementById("qr-container"));

qr-image is strictly for Node.js. It uses native modules and streams to output image buffers.

// qr-image: Node.js only
const qr = require('qr-image');
const pngBuffer = qr.imageSync('https://example.com', { type: 'png' });
// Send pngBuffer in HTTP response or save to disk

qrcode, qrcode-generator, and react-qr-code work in both environments—but with caveats:

  • qrcode uses feature detection to switch between canvas (browser) and PNGStream (Node.js).
  • qrcode-generator is pure JS and outputs strings or matrices—no rendering built-in.
  • react-qr-code is React-specific, so while it can be used with SSR (like Next.js), it’s primarily a client-side component.
// qrcode: works in both
import QRCode from 'qrcode';

// Browser: returns data URL
QRCode.toDataURL('https://example.com', (err, url) => {
  document.getElementById('qr').src = url;
});

// Node.js: returns PNG buffer
QRCode.toBuffer('https://example.com', (err, buffer) => {
  // write buffer to file
});

🎨 Styling and Customization Capabilities

If you just need a functional QR code, any library will do. But if branding matters, your options narrow quickly.

qr-code-styling leads in visual customization. It supports:

  • Custom foreground/background colors
  • Rounded dots
  • Embedded logos
  • Gradient fills
  • Dot and corner square styling
// qr-code-styling: advanced styling
new QRCode({
  data: "https://example.com",
  width: 300,
  height: 300,
  dotsOptions: {
    color: "#4267b2",
    type: "rounded"
  },
  backgroundOptions: {
    color: "#f5f6f7"
  },
  image: "/logo.png",
  imageOptions: {
    crossOrigin: "anonymous"
  }
});

react-qr-code and qrcode-generator offer almost no styling:

  • react-qr-code accepts fgColor and bgColor props only.
  • qrcode-generator returns raw SVG/HTML—you’d have to parse and modify it yourself.
// react-qr-code: minimal styling
<QRCode value="https://example.com" fgColor="#000" bgColor="#fff" />
// qrcode-generator: raw output
import qrcode from 'qrcode-generator';
const qr = qrcode(0, 'M');
qr.addData('https://example.com');
qr.make();
const svg = qr.createSvgTag(); // string you must inject manually

qrcode allows basic color control in SVG mode via options, but no logo embedding or shape changes.

// qrcode: limited SVG styling
QRCode.toString('https://example.com', {
  type: 'svg',
  color: { dark: '#333', light: '#eee' }
}, (err, svg) => {
  // inject svg string into DOM
});

qr-image has no styling options beyond size and margin—designed for utility, not design.

📤 Output Formats Supported

Different libraries produce different outputs:

PackageSVGPNGCanvasTerminalEPS/PDF
qr-code-styling❌¹
qr-image
qrcode
qrcode-generator✅²
react-qr-code

¹ qr-code-styling can be converted to PNG via canvas export, but it’s not built-in.
² qrcode-generator outputs SVG as a string, not a DOM element.

For example, generating a PNG in Node.js:

// qr-image
const png = qr.imageSync('text', { type: 'png' });

// qrcode
QRCode.toBuffer('text', { type: 'png' }, (err, buf) => { /*...*/ });

// qr-code-styling → not possible (browser-only)

⚙️ API Style and Developer Experience

The way you interact with each library varies significantly.

qr-code-styling uses an imperative class API—you create an instance and call methods like .append() or .download().

react-qr-code is fully declarative—just drop a component in your JSX.

qrcode and qr-image use callback-based or synchronous functions.

qrcode-generator requires manual steps: create instance → add data → make → render.

// qrcode-generator: verbose but explicit
const qr = qrcode(4, 'M');
qr.addData('Hello');
qr.make();
const html = qr.createTableTag(4); // returns HTML string

In contrast, react-qr-code is refreshingly simple:

<QRCode value="Hello" size={256} />

🧪 Error Correction and Encoding Control

All libraries support standard QR error correction levels (L, M, Q, H), but access differs:

  • qrcode and qr-image: pass errorCorrectionLevel in options.
  • qrcode-generator: specify level in constructor (qrcode(version, errorLevel)).
  • qr-code-styling: uses qrOptions.errorCorrectionLevel.
  • react-qr-code: accepts level prop ('L' | 'M' | 'Q' | 'H').
// qrcode
QRCode.toDataURL('text', { errorCorrectionLevel: 'H' }, cb);

// react-qr-code
<QRCode value="text" level="H" />

🛑 When Not to Use Each Package

  • Avoid qr-image in frontend code—it won’t work.
  • Avoid qr-code-styling if you need PNG output or server-side rendering.
  • Avoid qrcode-generator if you want plug-and-play image generation—it’s a toolkit, not a product.
  • Avoid react-qr-code if you’re not using React or need advanced styling.
  • Avoid qrcode only if you need pixel-perfect branded designs—its styling is basic.

💡 Real-World Recommendations

  • Marketing landing page with branded QR?qr-code-styling
  • Backend service emailing QR attachments?qr-image
  • Universal app needing PNG + SVG + terminal?qrcode
  • Building a custom QR renderer?qrcode-generator
  • React dashboard showing user QR codes?react-qr-code

Each library solves a specific slice of the QR problem. Match your constraints—environment, output, and design needs—to pick the right tool.

How to Choose: qr-code-styling vs qr-image vs qrcode vs qrcode-generator vs react-qr-code

  • qr-code-styling:

    Choose qr-code-styling when you need highly customizable, visually rich QR codes in the browser—such as branded codes with logos, colored modules, or gradient fills. It’s ideal for marketing campaigns or user-facing apps where aesthetics matter, but it only works in browser environments and doesn’t support raster formats like PNG directly. Avoid it if you need server-side generation or simple, unstyled codes.

  • qr-image:

    Choose qr-image only for Node.js server-side applications that require generating QR codes as image files (PNG, SVG, EPS, or PDF). It’s well-suited for backend services that email QR codes or embed them in documents, but it cannot run in the browser and offers no styling beyond basic size and margin control. Do not use it in frontend projects.

  • qrcode:

    Choose qrcode when you need a versatile, cross-environment solution that works reliably in both browsers and Node.js, with support for multiple output formats (canvas, SVG, PNG, UTF8). It’s battle-tested, supports error correction levels, and handles encoding options well. Use it for general-purpose QR generation where moderate customization suffices and you need flexibility across platforms.

  • qrcode-generator:

    Choose qrcode-generator when you want a minimal, dependency-free core QR engine that gives you full control over the matrix data or lets you render simple SVG/HTML manually. It’s perfect for lightweight integrations, educational purposes, or when you’re building your own renderer on top. Avoid it if you need ready-to-use image outputs or advanced styling out of the box.

  • react-qr-code:

    Choose react-qr-code when you’re in a React application and need a simple, declarative way to render an SVG QR code with minimal setup. It’s tiny, fast, and integrates seamlessly with React’s component model, but offers no visual customization beyond size and error correction. Ideal for internal tools, admin panels, or any scenario where functionality trumps design.

README for qr-code-styling

QR Code Styling

Version

JavaScript library for generating QR codes with a logo and styling.

Try it here https://qr-code-styling.com

If you have issues / suggestions / notes / questions, please open an issue or contact me. Let's create a cool library together.

Examples

Extensions

If you would like to use additional stiles, you can connect extensions.

qr-border-plugin

Installation

npm install qr-code-styling

Usage

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>QR Code Styling</title>
    <script type="text/javascript" src="https://unpkg.com/qr-code-styling@1.5.0/lib/qr-code-styling.js"></script>
</head>
<body>
<div id="canvas"></div>
<script type="text/javascript">

    const qrCode = new QRCodeStyling({
        width: 300,
        height: 300,
        type: "svg",
        data: "https://www.facebook.com/",
        image: "https://upload.wikimedia.org/wikipedia/commons/5/51/Facebook_f_logo_%282019%29.svg",
        dotsOptions: {
            color: "#4267b2",
            type: "rounded"
        },
        backgroundOptions: {
            color: "#e9ebee",
        },
        imageOptions: {
            crossOrigin: "anonymous",
            margin: 20
        }
    });

    qrCode.append(document.getElementById("canvas"));
    qrCode.download({ name: "qr", extension: "svg" });
</script>
</body>
</html>

React example (Codesandbox)

Angular example (Codesandbox)


React example (source)

Angular example (source)

Vue example (source)

Node.js example (source)

Next.js example (source)


API Documentation

QRCodeStyling instance

new QRCodeStyling(options) => QRCodeStyling

ParamTypeDescription
optionsobjectInit object

options structure

PropertyTypeDefault ValueDescription
widthnumber300Size of canvas
heightnumber300Size of canvas
typestring ('canvas' 'svg')canvasThe type of the element that will be rendered
shapestring (`'square' 'circle')squareThe shape of the qr-code, circle shape adds rundom extra dots arround
datastringThe data will be encoded to the QR code
imagestringThe image will be copied to the center of the QR code
marginnumber0Margin around canvas
qrOptionsobjectOptions will be passed to qrcode-generator lib
imageOptionsobjectSpecific image options, details see below
dotsOptionsobjectDots styling options
cornersSquareOptionsobjectSquare in the corners styling options
cornersDotOptionsobjectDots in the corners styling options
backgroundOptionsobjectQR background styling options
nodeCanvasnode-canvasOnly specify when running on a node server for canvas type, please refer to node section below
jsDomjsdomOnly specify when running on a node server for svg type, please refer to node section below

options.qrOptions structure

PropertyTypeDefault Value
typeNumbernumber (0 - 40)0
modestring ('Numeric' 'Alphanumeric' 'Byte' 'Kanji')
errorCorrectionLevelstring ('L' 'M' 'Q' 'H')'Q'

options.imageOptions structure

PropertyTypeDefault ValueDescription
hideBackgroundDotsbooleantrueHide all dots covered by the image
imageSizenumber0.4Coefficient of the image size. Not recommended to use ove 0.5. Lower is better
marginnumber0Margin of the image in px
crossOriginstring('anonymous' 'use-credentials')Set "anonymous" if you want to download QR code from other origins.
saveAsBlobbooleantrueSaves image as base64 blob in svg type, see bellow

When QR type is svg, the image may not load in certain applications as it is saved as a url, and some svg applications will not render url images for security reasons. Setting saveAsBlob to true will instead save the image as a blob, allowing it to render correctly in more places, but will also increase the file size.

options.dotsOptions structure

PropertyTypeDefault ValueDescription
colorstring'#000'Color of QR dots
gradientobjectGradient of QR dots
typestring ('rounded' 'dots' 'classy' 'classy-rounded' 'square' 'extra-rounded')'square'Style of QR dots
roundSizebooleantrueWhether to round dots size to integer. true value might create extra margin around qr code. If false, shape-rendering="crispEdges" will be applied to SVG element.

options.backgroundOptions structure

PropertyTypeDefault Value
colorstring ('#fff' 'rgb(255,255,255)' 'transparent')'#fff'
gradientobject

options.cornersSquareOptions structure

PropertyTypeDefault ValueDescription
colorstringColor of Corners Square
gradientobjectGradient of Corners Square
typestring ('dot' 'square' 'extra-rounded' 'rounded' 'dots' 'classy' 'classy-rounded')Style of Corners Square

options.cornersDotOptions structure

PropertyTypeDefault ValueDescription
colorstringColor of Corners Dot
gradientobjectGradient of Corners Dot
typestring ('dot' 'square' 'rounded' 'dots' 'classy' 'classy-rounded' 'extra-rounded')Style of Corners Dot

Gradient structure

options.dotsOptions.gradient

options.backgroundOptions.gradient

options.cornersSquareOptions.gradient

options.cornersDotOptions.gradient

PropertyTypeDefault ValueDescription
typestring ('linear' 'radial')"linear"Type of gradient spread
rotationnumber0Rotation of gradient in radians (Math.PI === 180 degrees)
colorStopsarray of objectsGradient colors. Example [{ offset: 0, color: 'blue' }, { offset: 1, color: 'red' }]

Gradient colorStops structure

options.dotsOptions.gradient.colorStops[]

options.backgroundOptions.gradient.colorStops[]

options.cornersSquareOptions.gradient.colorStops[]

options.cornersDotOptions.gradient.colorStops[]

PropertyTypeDefault ValueDescription
offsetnumber (0 - 1)Position of color in gradient range
colorstringColor of stop in gradient range

QRCodeStyling methods

QRCodeStyling.append(container) => void

ParamTypeDescription
containerDOM elementThis container will be used for appending of the QR code

QRCodeStyling.getRawData(extension) => Promise<Blob>

ParamTypeDefault ValueDescription
extensionstring ('png' 'jpeg' 'webp' 'svg')'png'Blob type on browser, Buffer type on Node

QRCodeStyling.update(options) => void

ParamTypeDescription
optionsobjectThe same options as for initialization

QRCodeStyling.applyExtension(extension) => void

ParamTypeDescription
extension(svg, options) => voidExtension is a function that takes svg and previously applied options and modifies an svg

applyExtension example

const extension = (svg, options) => {
    const { width, height } = options;
    const size = Math.min(width, height);
    const border = document.createElementNS("http://www.w3.org/2000/svg", "rect");
    const borderAttributes = {
        "fill": "none",
        "x": (width - size + 40) / 2,
        "y": (height - size + 40) / 2,
        "width": size - 40,
        "height": size - 40,
        "stroke": 'black',
        "stroke-width": 40,
        "rx": 100,
    };
    Object.keys(borderAttributes).forEach(attribute => {
      border.setAttribute(attribute, borderAttributes[attribute]);
    });
    svg.appendChild(border);
};

QRCodeStyling.deleteExtension() => void

QRCodeStyling.download(downloadOptions) => Promise<void>

ParamTypeDescription
downloadOptionsobjectOptions with extension and name of file (not required)

Promise returned will resolve into the data URI of the QR code image.

downloadOptions structure

PropertyTypeDefault ValueDescription
namestring'qr'Name of the downloaded file
extensionstring ('png' 'jpeg' 'webp' 'svg')'png'File extension

Building this repo

If you get an error running npm install referring to node-pre-gyp, this is caused by an attempt to compile the canvas dependency. See Compiling instructions in the README. For example on MacOS you need to install dependencies: brew install pkg-config cairo pango libpng jpeg giflib librsvg pixman.

Node Support

You can use this on a node server by passing through the node-canvas or jsdom object depending if your creating a non-svg or svg respectively. You must pass both if using imageOptions.saveAsBlob.

Calling getRawData in node will return a Buffer instead of a Blob.

const { QRCodeStyling } = require("qr-code-styling/lib/qr-code-styling.common.js");
const nodeCanvas = require("canvas");
const { JSDOM } = require("jsdom");
const fs = require("fs");

const options = {
    width: 300,
    height: 300,
    data: "https://www.facebook.com/",
    image: "https://upload.wikimedia.org/wikipedia/commons/5/51/Facebook_f_logo_%282019%29.svg",
    dotsOptions: {
        color: "#4267b2",
        type: "rounded"
    },
    backgroundOptions: {
        color: "#e9ebee",
    },
    imageOptions: {
        crossOrigin: "anonymous",
        margin: 20
    }
}

// For canvas type
const qrCodeImage = new QRCodeStyling({
    jsdom: JSDOM, // this is required
    nodeCanvas, // this is required,
    ...options,
    imageOptions: {
        saveAsBlob: true,
        crossOrigin: "anonymous",
        margin: 20
    },
});

qrCodeImage.getRawData("png").then((buffer) => {
  fs.writeFileSync("test.png", buffer);
});

// For svg type
const qrCodeSvg = new QRCodeStyling({
    jsdom: JSDOM, // this is required
    type: "svg",
    ...options
});

qrCodeSvg.getRawData("svg").then((buffer) => {
  fs.writeFileSync("test.svg", buffer);
});

// For svg type with the inner-image saved as a blob
// (inner-image will render in more places but file will be larger)
const qrCodeSvgWithBlobImage = new QRCodeStyling({
    jsdom: JSDOM, // this is required
    nodeCanvas, // this is required
    type: "svg",
    ...options,
    imageOptions: {
        saveAsBlob: true,
        crossOrigin: "anonymous",
        margin: 20
    }
});

qrCodeSvgWithBlobImage.getRawData("svg").then((buffer) => {
  fs.writeFileSync("test_blob.svg", buffer);
});

License

MIT License. Copyright (c) 2021 Denys Kozak