qrGrid: Custom QR Code Generator with Logos and Gradients

Category: Javascript | June 10, 2026
Authoryadav-saurabh
Last UpdateJune 10, 2026
LicenseMIT
Tags
Views0 views
qrGrid: Custom QR Code Generator with Logos and Gradients

qrGrid is a zero-dependency TypeScript QR code generator that creates raw QR module data for custom Canvas, SVG, framework, server-side, and CLI rendering.

You can use it to generate branded QR codes with custom module shapes, gradients, finder pattern colors, and logos.

Features:

  • Encodes data with Reed-Solomon error correction at four levels (L, M, Q, H).
  • Exposes the full module grid as a flat Uint8Array for custom canvas and SVG rendering.
  • Style helpers for circular, smooth-edge, and rounded-corner module shapes.
  • Native components for React, Vue, and Angular with canvas and SVG variants.
  • Generates SVG strings server-side in Node.js for emails, PDFs, and API responses.
  • Supports solid colors, gradient fills, and separate color settings for finder and data modules.
  • Embeds logo images at the center with configurable size and overlap options.
  • Outputs QR codes to the terminal or saves SVG files from the command line.
  • Selects the smallest QR version that fits the encoded data at the chosen error correction level.
  • Covers the full QR specification including alignment patterns, timing patterns, and all eight masking rules.

Use Cases:

  • Branded QR codes for marketing materials that need custom colors, shapes, and embedded logos.
  • Invoice or email PDFs generated on the server with dynamic QR codes containing payment links.
  • Terminal-based QR display for CLI tools and development scripts.
  • Product dashboards that let users style and download QR codes directly in the browser.

How To Use It

Installation

The @qrgrid/core package is the encoding engine and the only required dependency for custom rendering.

npm install @qrgrid/core

Install @qrgrid/styles to use the built-in module shape helpers.

npm install @qrgrid/styles

Framework-specific packages install independently.

# React
npm install @qrgrid/react
# Vue 3
npm install @qrgrid/vue
# Angular
npm install @qrgrid/angular
# Node.js server-side SVG
npm install @qrgrid/server

The CLI requires no installation.

npx @qrgrid/cli -i "https://example.com"

Basic Usage

The QR constructor takes a string and returns an object with the full module grid. This example renders a QR code for a product URL on a <canvas> element.

qr.data holds a 1 for every dark module and a 0 for every light module. The size calculation pads the canvas so the required quiet zone fits on all sides.

<canvas id="productQr" width="400" height="400"></canvas>
import { QR } from "@qrgrid/core";
const qr = new QR("https://myshop.com/products/laptop-stand-pro");
const canvas = document.getElementById("productQr");
const ctx = canvas.getContext("2d");
// Calculate module size and total canvas dimensions including quiet zone
const size = Math.floor(400 / (qr.gridSize + 1.5));
const border = Math.ceil(size * qr.gridSize - 400) + size * 2;
canvas.height = 400 + border;
canvas.width = 400 + border;
// Render each dark module as a filled rectangle
ctx.fillStyle = "#111111";
let x = size, y = size;
for (let i = 0; i < qr.data.length; i++) {
  if (qr.data[i]) {
    ctx.fillRect(x, y, size, size);
  }
  x += size;
  if (i % qr.gridSize === qr.gridSize - 1) {
    x = size;
    y += size;
  }
}
// Paint the background behind all modules
ctx.globalCompositeOperation = "destination-over";
ctx.fillStyle = "#ffffff";
ctx.fillRect(0, 0, canvas.width, canvas.height);

Advanced Usages

SVG Rendering

SVG output suits projects that need QR codes to scale to any size for print or high-DPI displays. This snippet builds a compact path string from all dark modules and sets it on a single <path> element, keeping the SVG markup lightweight regardless of QR version.

<svg id="downloadQr" xmlns="http://www.w3.org/2000/svg">
  <path id="qrModules" />
</svg>
import { QR } from "@qrgrid/core";
const qr = new QR("https://myapp.com/downloads/annual-report-2024");
const svg = document.getElementById("downloadQr");
const pathEl = document.getElementById("qrModules");
const size = Math.floor(400 / (qr.gridSize + 1.5));
const border = Math.ceil(size * qr.gridSize - 400) + size * 2;
const total = 400 + border;
svg.setAttribute("width", total);
svg.setAttribute("height", total);
svg.setAttribute("viewBox", `0 0 ${total} ${total}`);
svg.style.background = "#ffffff";
let x = size, y = size, d = "";
for (let i = 0; i < qr.data.length; i++) {
  if (qr.data[i]) {
    // Each dark module becomes a closed rectangle path command
    d += `M${x} ${y}v${size}h${size}v-${size}z`;
  }
  x += size;
  if (i % qr.gridSize === qr.gridSize - 1) {
    x = size;
    y += size;
  }
}
pathEl.setAttribute("d", d);
pathEl.setAttribute("fill", "#111111");

Custom Module Shapes

Circular or smooth-edge modules suit branded QR codes on marketing materials or product packaging. The @qrgrid/styles package provides drawing functions that replace ctx.fillRect in the render loop. No new loop structure is required.

import { QR } from "@qrgrid/core";
import { drawCircle, drawSmoothEdges } from "@qrgrid/styles/canvas";
const qr = new QR("https://mybrand.com/spring-launch");
// ... canvas setup as in Basic Usage above ...
let x = size, y = size;
for (let i = 0; i < qr.data.length; i++) {
  if (qr.data[i]) {
    // Replace ctx.fillRect with a shape function from @qrgrid/styles
    drawCircle(ctx, { index: i, x, y, size });
    // Use drawSmoothEdges for connected smooth shapes instead
    // drawSmoothEdges(ctx, { index: i, x, y, size }, qr);
  }
  x += size;
  if (i % qr.gridSize === qr.gridSize - 1) { x = size; y += size; }
}

The SVG equivalents return path string fragments to append inside your d string.

import { getCirclePath, getSmoothEdgesPath } from "@qrgrid/styles/svg";
// Inside the SVG path loop:
if (qr.data[i]) {
  d += getCirclePath(x, y, size);
  // Or: d += getSmoothEdgesPath({ index: i, x, y, size }, qr);
}

Coloring Finder Patterns

Brand color systems often call for the three finder squares to use an accent color separate from the data area. The qr.reservedBits object identifies each module’s structural type. Check the type in the render loop before setting the fill color.

import { QR, ReservedBits } from "@qrgrid/core";
const qr = new QR("https://myconf.io/events/summit-2025");
// ... canvas setup ...
let x = size, y = size;
for (let i = 0; i < qr.data.length; i++) {
  if (qr.data[i]) {
    // Apply accent color to finder squares, base color to all other modules
    if (qr.reservedBits[i]?.type === ReservedBits.FinderPattern) {
      ctx.fillStyle = "#c62828"; // brand accent
    } else {
      ctx.fillStyle = "#1a237e"; // data module color
    }
    ctx.fillRect(x, y, size, size);
  }
  x += size;
  if (i % qr.gridSize === qr.gridSize - 1) { x = size; y += size; }
}

React Component

React projects that need a component ready to drop into JSX use the @qrgrid/react package. The Qr component from @qrgrid/react/canvas manages the draw loop internally and accepts module styling through props, including logo embedding.

import { Qr } from "@qrgrid/react/canvas";
import { dotModuleStyle } from "@qrgrid/styles/canvas/styles";
function CheckoutQrCode() {
  return (
    <Qr
      input="https://myshop.com/checkout/session-48291"
      bgColor="#fafafa"
      color="#212121"
      moduleStyle={dotModuleStyle}
      qrOptions={{ errorCorrection: "H" }}
      image={{ src: "/assets/brand-icon.png", overlap: false, sizePercent: 18 }}
    />
  );
}

For SVG output, import Qr from @qrgrid/react/svg instead.

Vue 3 Component

Vue 3 projects use the same component API through the @qrgrid/vue package. Import Qr from @qrgrid/vue/canvas and pass a style function as a prop; the component handles the draw loop internally.

<script setup>
import { Qr } from "@qrgrid/vue/canvas";
import { smoothModuleStyle } from "@qrgrid/styles/canvas/styles";
</script>
<template>
  <Qr
    input="https://myapp.com/tickets/event-39182"
-moduleStyle="smoothModuleStyle"
    bgColor="#f5f5f5"
    color="#1b5e20"
  />
</template>

Angular Component

Angular projects use the @qrgrid/angular package. Add CanvasQr to the module’s imports array and use the <qr> selector in templates.

import { NgModule } from "@angular/core";
import { CanvasQr } from "@qrgrid/angular";
@NgModule({
  imports: [CanvasQr],
})
export class AppModule {}
<!-- Template usage -->
<qr input="https://myapp.com/reports/q4-summary" />

Server-Side SVG Generation

PDF generation pipelines and HTML email templates often need QR codes built before the browser loads. The generateQr function from @qrgrid/server returns a complete SVG string synchronously. No DOM or canvas context is required.

import { generateQr } from "@qrgrid/server";
const svg = generateQr("https://myapp.com/invoices/INV-00481", {
  size: 500,
  qrOptions: { errorCorrection: "H" },
  color: {
    finder: "#b71c1c",   // accent color for finder squares
    codeword: "#212121"  // near-black data modules
  },
});
// Embed in an HTML email or pass to a PDF library
res.setHeader("Content-Type", "image/svg+xml");
res.send(svg);

CLI Usage

The CLI outputs a QR code to the terminal or saves it as an SVG file. No install step is needed before running it.

# Print a QR code to the terminal
npx @qrgrid/cli -i "https://myapp.com/referral/ALEX2025"
# Save as an SVG file
npx @qrgrid/cli -i "https://myapp.com/pricing" -f pricing-qr.svg
# Generate a WiFi QR code
npx @qrgrid/cli -i "WIFI:T:WPA;S:GuestNetwork;P:C0nf3r3nc3R00m;;" -f wifi-access.svg

All configuration options

  • input (string): QR content for React, Vue, and Angular component usage.
  • bgColor (string): Background color for component-rendered QR codes.
  • color (string | object | function): Module color for the QR code. A string applies one color. An object can define separate finder and codeword colors. A Canvas callback can return a gradient or another Canvas fill style.
  • color.finder (string): Color for finder pattern modules.
  • color.codeword (string): Color for regular data modules.
  • moduleStyle (function): Drawing style helper for component output, such as dot or smooth module styles from the styles package.
  • qrOptions (object): Encoding options passed to the QR engine.
  • qrOptions.errorCorrection ("L" | "M" | "Q" | "H"): Error correction level. Use "H" when a logo or visual styling covers part of the QR grid.
  • image (object): Center image settings for component output.
  • image.src (string): Path for the center logo or image.
  • image.overlap (boolean): Controls whether the center image may overlap QR modules.
  • image.sizePercent (number): Logo size as a percentage of the QR output.
  • size (number): Server-side SVG output size in pixels.
  • -i (string): CLI input value.
  • -f (string): CLI output file path.

Core API Methods

import { QR, ReservedBits } from "@qrgrid/core";
// Create a QR instance from a non-empty string.
const customerQr = new QR("https://example.com/customers/8421", {
  errorCorrection: "H",
});
// Read the flat module array. 1 means dark. 0 means light.
const modules = customerQr.data;
// Read the grid width and height in modules.
const moduleCount = customerQr.gridSize;
// Read the selected QR version.
const version = customerQr.version;
// Read the selected error correction level.
const correctionLevel = customerQr.errorCorrection;
// Read the input segments chosen by the encoder.
const segments = customerQr.segments;
// Read metadata for structural QR modules.
const firstModuleInfo = customerQr.reservedBits[0];
// Check whether a module belongs to a finder pattern.
const isFinderPattern =
  firstModuleInfo?.type === ReservedBits.FinderPattern;
// Read the selected mask pattern.
const maskPattern = customerQr.maskPatten;

Alternatives:

FAQs:

Q: Which error correction level should I use when embedding a logo?
A: Use "H". It provides the highest redundancy at 30% data recovery capacity. A logo that covers the center area can obscure modules, and the H level gives scanners enough data to reconstruct the full code.

Q: Can I use qrGrid in a Next.js or SSR project?
A: Yes, with one caveat. Use @qrgrid/server on the server side; it generates SVG strings with no DOM access. The canvas and browser SVG packages depend on browser APIs and must run only on the client.

Q: My QR code renders but scanners fail to read it. What should I check?
A: Two common causes are a missing quiet zone and a miscalculated module size. The basic usage snippet includes border math that adds the required white margin around the code. Modifying that calculation breaks the quiet zone. Set errorCorrection to "H" if a logo partially covers the center.

You Might Be Interested In:


Leave a Reply