Qr Code
React data-displayStatic QR code renderer — pass `value` and a size, get an SVG. Useful for sign-in links, share URLs, and Wi-Fi credentials. No dependencies on a heavy QR library.
Also available for Vue ->Installation
$ pnpm dlx shadcn@latest add https://react.uipkge.dev/r/react/qr-code.json$ npx shadcn@latest add https://react.uipkge.dev/r/react/qr-code.json$ yarn dlx shadcn@latest add https://react.uipkge.dev/r/react/qr-code.json$ bunx shadcn@latest add https://react.uipkge.dev/r/react/qr-code.json
Or with the named registry:
npx shadcn@latest add @uipkge-react/qr-code
Examples
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
value | string | — | required |
type | QRCodeType | — | optional |
size | number | — | optional |
color | string | — | optional |
bgColor | string | — | optional |
icon | string | — | optional |
iconSize | number | { width: number; height: number } | — | optional |
errorLevel | QRCodeErrorLevel | — | optional |
bordered | boolean | — | optional |
status | QRCodeStatus | — | optional |
marginSize | number | — | optional |
className | string | — | optional |
onRefresh Fired when the "Refresh" action of the expired overlay is clicked. | () => void | — | optional |
extra Overrides the default download button (parity with the Vue `extra` slot). | React.ReactNode | — | optional |
Dependencies
Files (2)
-
components/ui/qr-code/QrCode.tsx 5.9 kB
'use client' import * as React from 'react' // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore -- qrcode ships no types unless @types/qrcode (a devDependency) is installed; @ts-ignore stays valid either way import QRCodeLib from 'qrcode' import { Loader2, RotateCcw, Check, ScanLine } from 'lucide-react' import { cn } from '@/lib/utils' export type QRCodeType = 'canvas' | 'svg' export type QRCodeStatus = 'active' | 'expired' | 'loading' | 'scanned' export type QRCodeErrorLevel = 'L' | 'M' | 'Q' | 'H' export interface QrCodeProps { value: string type?: QRCodeType size?: number color?: string bgColor?: string icon?: string iconSize?: number | { width: number; height: number } errorLevel?: QRCodeErrorLevel bordered?: boolean status?: QRCodeStatus marginSize?: number className?: string /** Fired when the "Refresh" action of the expired overlay is clicked. */ onRefresh?: () => void /** Overrides the default download button (parity with the Vue `extra` slot). */ extra?: React.ReactNode } const QrCode = React.forwardRef<HTMLDivElement, QrCodeProps>( ( { value, type = 'canvas', size = 160, color = '#000000', bgColor = '#ffffff', icon, iconSize, errorLevel = 'M', bordered = true, status = 'active', marginSize = 0, className, onRefresh, extra, }, ref, ) => { const [qrDataUrl, setQrDataUrl] = React.useState('') const [qrSvg, setQrSvg] = React.useState('') const iconDimensions = typeof iconSize === 'number' ? { width: iconSize, height: iconSize } : iconSize ?? { width: 40, height: 40 } React.useEffect(() => { let cancelled = false async function generateQR() { if (!value || status === 'loading') return try { const options = { width: size, margin: marginSize, color: { dark: color, light: bgColor }, errorCorrectionLevel: errorLevel, } if (type === 'svg') { const svg = await QRCodeLib.toString(value, { type: 'svg', ...options }) if (!cancelled) setQrSvg(svg) } else { const url = await QRCodeLib.toDataURL(value, options) if (!cancelled) setQrDataUrl(url) } } catch (e) { console.error('QR Code generation failed:', e) } } generateQR() return () => { cancelled = true } }, [value, type, size, color, bgColor, errorLevel, marginSize, status]) function downloadQR() { const link = document.createElement('a') link.download = `qrcode-${value.slice(0, 20)}.png` link.href = qrDataUrl link.click() } const statusOverlay = (() => { switch (status) { case 'expired': return { Icon: RotateCcw, text: 'Expired', action: onRefresh ?? null } case 'scanned': return { Icon: Check, text: 'Scanned', action: null } case 'loading': return { Icon: Loader2, text: 'Loading...', action: null } default: return null } })() return ( <div ref={ref} data-uipkge="" data-slot="qr-code" className={cn( 'inline-flex flex-col items-center gap-2', bordered && 'bg-background rounded-lg border p-4', className, )} > <div className="relative inline-flex items-center justify-center overflow-hidden" style={{ width: `${size}px`, height: `${size}px` }} > {/* QR Code */} {type === 'svg' && qrSvg ? ( <div className="size-full" dangerouslySetInnerHTML={{ __html: qrSvg }} /> ) : qrDataUrl ? ( <img src={qrDataUrl} alt={`QR Code for ${value}`} className="size-full" /> ) : null} {/* Icon overlay */} {icon && status === 'active' && ( <div className="absolute inset-0 flex items-center justify-center"> <div className="overflow-hidden rounded-md bg-white shadow-sm" style={{ width: `${iconDimensions.width}px`, height: `${iconDimensions.height}px` }} > <img src={icon} alt="" className="size-full object-cover" /> </div> </div> )} {/* Status overlay */} {statusOverlay && ( <div className="absolute inset-0 flex flex-col items-center justify-center gap-2 bg-white/90 backdrop-blur-sm"> <statusOverlay.Icon className={cn('size-8', status === 'loading' && 'animate-spin')} /> <span className="text-foreground text-sm font-medium">{statusOverlay.text}</span> {statusOverlay.action && ( <button type="button" className="bg-primary text-primary-foreground hover:bg-primary/90 focus-visible:ring-ring inline-flex items-center gap-1 rounded-md px-3 py-1 text-xs font-medium focus-visible:ring-2 focus-visible:outline-none" onClick={statusOverlay.action} > <ScanLine className="size-3" /> Refresh </button> )} </div> )} </div> {/* Download button (overridable via the `extra` prop) */} {extra !== undefined ? extra : type === 'canvas' && status === 'active' && qrDataUrl && ( <button type="button" className="text-muted-foreground hover:text-foreground focus-visible:ring-ring text-xs underline-offset-2 hover:underline focus-visible:ring-2 focus-visible:outline-none" onClick={downloadQR} > Download </button> )} </div> ) }, ) QrCode.displayName = 'QrCode' export { QrCode } -
components/ui/qr-code/index.ts 0.1 kB
export { QrCode, type QrCodeProps, type QRCodeType, type QRCodeStatus, type QRCodeErrorLevel } from './QrCode'
Raw manifest: https://react.uipkge.dev/r/react/qr-code.json