qr-code-styling vs qr.js vs qrcode.react vs qrious vs react-qr-code
QR Code Generation Libraries for Web Applications
qr-code-stylingqr.jsqrcode.reactqriousreact-qr-codeSimilar Packages:

QR Code Generation Libraries for Web Applications

qr-code-styling, qr.js, qrcode.react, qrious, and react-qr-code are all JavaScript libraries designed to generate QR codes in web applications, but they differ significantly in rendering approach, framework integration, customization capabilities, and maintenance status. These packages enable developers to embed scannable QR codes into UIs for purposes like sharing URLs, authentication tokens, or contact information. While some focus on raw canvas or SVG output with minimal dependencies, others provide React-specific components with declarative APIs. Understanding their technical trade-offs is essential for choosing the right tool based on your project’s rendering needs, design requirements, and framework constraints.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
qr-code-styling02,752516 kB110a year agoMIT
qr.js0---13 years agoMIT
qrcode.react04,242115 kB35a year agoISC
qrious01,625-439 years agoGPL-3.0
react-qr-code086713.8 kB138 months agoMIT

QR Code Libraries Compared: Rendering, Customization, and React Integration

Generating QR codes seems simple at first glance — just pass a string and get a square of black-and-white dots. But in real-world apps, you often need control over appearance, accessibility, performance, and framework integration. The five libraries under review take very different approaches. Let’s break them down by how they render, what you can customize, and how they fit into modern frontend workflows.

🖼️ Rendering Approach: Canvas vs SVG vs Raw Data

How a library draws the QR code affects everything from styling flexibility to accessibility.

qr-code-styling renders exclusively to SVG, giving you full vector control. This enables CSS styling, scaling without quality loss, and embedding of additional SVG elements like logos.

// qr-code-styling
import QRCodeStyling from "qr-code-styling";

const qrCode = new QRCodeStyling({
  width: 300,
  height: 300,
  data: "https://example.com",
  image: "/logo.svg", // embed logo
  dotsOptions: { type: "rounded" }
});

qrCode.append(document.getElementById("qr-container"));

qr.js doesn’t render anything — it only generates the raw QR matrix (a 2D boolean array). You must build your own renderer.

// qr.js
import qr from "qr.js";

const qrcode = qr("https://example.com");
const matrix = qrcode.matrix; // [[true, false, ...], [...]]

// Now draw to canvas manually
const canvas = document.getElementById("qr-canvas");
const ctx = canvas.getContext("2d");
matrix.forEach((row, y) => {
  row.forEach((cell, x) => {
    ctx.fillStyle = cell ? "#000" : "#fff";
    ctx.fillRect(x * 4, y * 4, 4, 4);
  });
});

qrcode.react supports both <canvas> and <svg> via the renderAs prop. Canvas is default; SVG is better for SSR and accessibility.

// qrcode.react
import QRCode from "qrcode.react";

// Canvas (default)
<QRCode value="https://example.com" />

// SVG (for SSR/accessibility)
<QRCode value="https://example.com" renderAs="svg" />

qrious (deprecated) renders only to HTML5 <canvas>. No SVG option, which limits scalability and accessibility.

// qrious (avoid in new projects)
import QRious from "qrious";

new QRious({
  element: document.getElementById("qr-canvas"),
  value: "https://example.com",
  size: 200
});

react-qr-code renders exclusively to accessible SVG, with built-in role="img" and support for title/aria-label.

// react-qr-code
import QRCode from "react-qr-code";

<QRCode
  value="https://example.com"
  size={256}
  title="Scan to visit example.com"
  aria-label="QR code for example.com"
/>

🎨 Customization: From Basic Colors to Brand Logos

Need more than black-on-white? Here’s what each library supports.

qr-code-styling leads in visual customization:

  • Dot shapes (square, rounded, dots, classy, etc.)
  • Corner square styles
  • Gradient fills (linear/radial)
  • Embedded logo image with padding control
  • Background image
// qr-code-styling: advanced styling
new QRCodeStyling({
  data: "https://example.com",
  dotsOptions: {
    color: "#4A90E2",
    type: "dots"
  },
  backgroundOptions: {
    color: "#F5F7FA"
  },
  image: "/brand-logo.png",
  imageOptions: { margin: 10 }
});

qrcode.react supports basic color and size adjustments:

  • fgColor / bgColor
  • size
  • Error correction level (level)
  • No logo or dot shape customization
// qrcode.react: basic styling
<QRCode
  value="https://example.com"
  fgColor="#2D3748"
  bgColor="#EDF2F7"
  size={200}
/>

react-qr-code offers similar basic styling but with better accessibility hooks:

  • fgColor / bgColor
  • size
  • title and aria-label for screen readers
  • No logo or advanced dot styling
// react-qr-code: accessible styling
<QRCode
  value="https://example.com"
  fgColor="#1A202C"
  bgColor="#FFFFFF"
  size={220}
  title="Example website QR code"
/>

qr.js provides zero built-in styling — you control every pixel when you implement your renderer.

qrious (deprecated) allowed basic color and size changes but nothing beyond that.

⚛️ React Integration: Declarative vs Imperative

If you’re using React, how the library fits into your component model matters.

qrcode.react and react-qr-code are true React components — they re-render automatically when props change and work with React’s reconciliation.

// Both update when `url` changes
function App({ url }) {
  return <QRCode value={url} />;
}

qr-code-styling is not React-native. You must manage its lifecycle imperatively (e.g., using useEffect and refs):

// qr-code-styling in React (manual)
import { useEffect, useRef } from "react";
import QRCodeStyling from "qr-code-styling";

function QRComponent({ value }) {
  const ref = useRef();
  const qrRef = useRef();

  useEffect(() => {
    if (!qrRef.current) {
      qrRef.current = new QRCodeStyling({ data: value });
      qrRef.current.append(ref.current);
    } else {
      qrRef.current.update({ data: value });
    }
  }, [value]);

  return <div ref={ref} />;
}

qr.js and qrious also require manual DOM management in React and aren’t optimized for component re-renders.

♿ Accessibility and SSR Considerations

For public-facing apps, QR codes should be accessible and work during server-side rendering.

  • react-qr-code shines here: SVG output includes role="img", supports title, and renders on the server.
  • qrcode.react supports SSR only when renderAs="svg"; canvas won’t work on the server.
  • qr-code-styling uses SVG but requires browser DOM APIs (document.createElementNS), so it won’t work during SSR — you’ll need dynamic imports or client-only rendering.
  • qr.js and qrious produce canvas output that isn’t accessible by default and doesn’t support SSR.

🚫 Deprecation Warning: Avoid qrious

According to its npm page and GitHub repo, qrious is deprecated and hasn’t been updated since 2017. It lacks TypeScript definitions, modern build tooling, and security updates. Do not use it in new projects.

📊 Summary Table

PackageRenderingReact ComponentCustomizationSSR SupportAccessibilityStatus
qr-code-stylingSVG❌ (imperative)✅✅✅ (logos, gradients)MediumActive
qr.jsRaw matrix❌ (you build it)✅*LowActive
qrcode.reactCanvas / SVG✅ (colors, size)✅ (SVG only)MediumActive
qriousCanvas✅ (basic)LowDeprecated
react-qr-codeSVG✅ (colors, size, A11y)✅✅Active

* qr.js supports SSR only if you implement a server-safe renderer (e.g., using sharp or svg strings).

💡 Final Recommendation

  • Need brand-aligned, eye-catching QR codes? → Use qr-code-styling, but wrap it properly in React and accept the SSR limitation.
  • Building a standard React app with basic QR needs? → Choose react-qr-code for best practices in accessibility and SSR, or qrcode.react if you prefer canvas fallbacks.
  • Require total control over rendering logic? → Use qr.js and build your own renderer tailored to your exact needs.
  • Maintaining legacy code with qrious? → Plan a migration to react-qr-code or qrcode.react.

In most modern React applications, react-qr-code offers the best balance of simplicity, accessibility, and correctness, while qr-code-styling is the go-to for marketing or branded experiences where visual polish matters more than SSR.

How to Choose: qr-code-styling vs qr.js vs qrcode.react vs qrious vs react-qr-code

  • qr-code-styling:

    Choose qr-code-styling if you need highly customizable, visually rich QR codes rendered as SVG with support for logos, rounded corners, gradient fills, and dot patterns. It works well in both vanilla JS and React (via ref or wrapper), but requires manual DOM handling in non-React contexts. Avoid it if you need lightweight output or server-side rendering, as it relies on browser DOM APIs and produces relatively large SVG markup.

  • qr.js:

    Choose qr.js if you want a minimal, dependency-free, pure JavaScript library that generates raw QR code matrices without any built-in rendering. It’s ideal for projects that need full control over how and where the QR code is displayed (e.g., custom canvas drawing, terminal output, or integration with other graphics libraries). However, you’ll need to implement your own renderer, which adds development overhead.

  • qrcode.react:

    Choose qrcode.react if you’re building a React application and need a simple, reliable component that renders QR codes to HTML <canvas> or <svg> with basic props like value, size, and bgColor. It’s actively maintained, supports SSR-friendly SVG mode, and integrates seamlessly with React’s lifecycle. Avoid it if you require advanced styling like custom dot shapes or embedded logos, as it offers limited visual customization.

  • qrious:

    Do not choose qrious for new projects — it is officially deprecated according to its npm page and GitHub repository, with no updates since 2017. While it once provided a straightforward canvas-based QR generator with basic color and size options, its outdated codebase lacks modern features, TypeScript support, and security patches. Migrate existing usage to alternatives like qrcode.react or react-qr-code.

  • react-qr-code:

    Choose react-qr-code if you need a modern, lightweight React component that renders clean, accessible SVG QR codes with good defaults and essential customization (e.g., size, fgColor, bgColor, level). It’s ideal for projects prioritizing accessibility (includes role="img" and aria-label), SSR compatibility, and minimal bundle impact. Avoid it if you need complex visual enhancements like logos or non-standard dot shapes, as it focuses on simplicity and standards compliance.

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