QR Code

A flexible QR code generator with square/dotted module shapes, solid or gradient fills, and a center logo overlay slot — the same building blocks as Telegram's QR share sheet.

Last updated August 16, 2026

Overview

Installation

$ npx shadcn@latest add https://ui.persian-labs.ir/r/qr-code.json

Usage

import {
  QrCode,
  QrCodeDownload,
  QrCodeFrame,
} from "@/components/ui/qr-code"
 
export function Example() {
  return (
    <QrCode value="https://ui.persian-labs.ir">
      <QrCodeFrame />
      <QrCodeDownload fileName="qr-code.png" mimeType="image/png">
        Download
      </QrCodeDownload>
    </QrCode>
  )
}

Variant

The encoded matrix is traced into a single SVG <path>, one dark module at a time. The dotted variant is built by rendering that path invisibly inside an SVG <mask>, which turns it into a reusable stencil — the actual visible fill (a tiled dot pattern here) is painted through the mask, so it's clipped to exactly the QR module shape without needing per-cell coordinates.

Gradient Color

The same masking technique lets color accept a gradient config instead of a solid CSS color, rendered as an SVG <linearGradient> / <radialGradient> painted through the same mask. Keep enough contrast between the pattern and the frame's white background — a low-contrast gradient (e.g. light-on-light) makes the code unreliable or impossible to scan.

QrCodeOverlay renders any content — an image, an icon, a brand mark — centered over the code, independent of the variant/color system above. It's aria-hidden by default since the QR code itself carries the meaning, not the logo.

Loading Skeleton

QrCodeSkeleton matches QrCodeFrame's default footprint exactly, so swapping between the two while the encoded value loads causes zero layout shift.

Download

QrCodeDownload exports the frame as an image client-side — the SVG frame is serialized, drawn onto an offscreen canvas, and saved as a PNG/JPEG/ WebP through a temporary download link. It renders as a styled button by default — pass an icon and visible text as children (as in the examples above), or an aria-label if you render it icon-only.

RTL

QR data itself is direction-agnostic visual data, so the code renders identically regardless of the surrounding document direction — the labels and download button around it are what need to follow the page's direction.

API Reference

QrCode

QrCodeFrame

QrCodeOverlay

QrCodeDownload

QrCodeSkeleton