Lightweight, fully customizable React QR code library — pure SVG, zero dependencies, built from scratch.
- Pure SVG — no canvas, no raster images, scales perfectly at any size
- Zero runtime dependencies — QR encoding implemented from scratch (ISO/IEC 18004)
- Fully typed — written in TypeScript with strict mode
- 3 dot styles — square, circle, and snake-connected rounded
- Customizable corners — independent style and color for each finder pattern part
- Logo support — embed an image or any React element in the center
- Export helpers —
toSVGString()for SSR/server use,toDataURL()for PNG/JPEG download - Tree-shakeable — named exports only, ESM + CJS output
pnpm add @ttsalpha/qrcodeReact 18+ is required as a peer dependency.
import { QRCode } from '@ttsalpha/qrcode';
export default function App() {
return <QRCode value="https://example.com" />;
}<QRCode
value="https://example.com"
size={256}
dotStyle="rounded"
dotColor="#1a1a2e"
corner={{
square: { style: 'extra-rounded', color: '#e94560' },
}}
/><QRCode
value="https://example.com"
dotStyle="rounded"
corner={{ square: { style: 'extra-rounded' } }}
logo={{
src: '/logo.png',
size: 0.5,
margin: 4,
}}
/>
logo.sizeis a 0–1 scale relative to the maximum safe area — the component auto-picks the lowest ECL that can support the requested size. Setqr.errorCorrectionLevelexplicitly only if you need to override this. Non-square logos are supported; aspect ratio is detected automatically.
<QRCode
value="https://example.com"
logo={{
element: <MyIcon size={40} />,
}}
qr={{ errorCorrectionLevel: 'H' }}
/>| Prop | Type | Default | Description |
|---|---|---|---|
value |
string |
— | The data to encode (required) |
size |
number |
256 |
SVG size in pixels |
margin |
number |
4 |
Quiet zone size in modules |
dotStyle |
DotStyle |
'square' |
Style of data modules |
dotColor |
string |
'#000000' |
Color of data modules |
backgroundColor |
string |
'#ffffff' |
Background color ('transparent' ok) |
corner |
CornerOptions |
— | Finder pattern corner styles |
logo |
LogoOptions |
— | Logo in the center of the QR code |
qr |
QROptions |
— | QR encoding options |
className |
string |
— | CSS class on the <svg> element |
style |
CSSProperties |
— | Inline style on the <svg> element |
| Value | Description |
|---|---|
square |
Full square (default) |
circle |
Full circle |
rounded |
Rounded corners; adjacent modules connect smoothly (snake/fluid effect) |
interface CornerOptions {
dot?: {
style?: 'square' | 'rounded' | 'circle'; // inner 3×3 block
color?: string;
};
square?: {
style?: 'square' | 'rounded' | 'extra-rounded' | 'circle'; // outer 7×7 ring
color?: string;
};
}When
corner.dot.styleis not set, the inner dot style defaults based on the square style:extra-rounded→rounded,circle→circle, others →square.
interface LogoOptions {
src?: string; // https, relative path, blob:, or data:image/… URI
element?: ReactNode; // takes priority over src if both provided
size?: number; // 0–1 relative to max safe area, default: 0.4; ECL auto-picked; aspect ratio auto-detected
margin?: number; // space between logo and edge of cleared area; larger = smaller logo
hideDots?: boolean; // clear QR dots behind the logo area, default: true
}ECL is auto-picked based on
logo.size— no need to setqr.errorCorrectionLevelmanually. The size scale maps to empirical safe linear limits:size ≤ 0.25→ ECL L (logo ≤ 15% width),≤ 0.44→ ECL M (≤ 20%),≤ 0.69→ ECL Q (≤ 25%),≤ 1.0→ ECL H (≤ 30%). If ECL is set explicitly, the logo size is clamped to that ECL's limit. For landscape logos the height is reduced proportionally — the logo is never wider than the QR itself.
Security:
javascript:and non-imagedata:URIs insrcare silently rejected. Never pass unsanitised user input aselement— it is rendered verbatim inside a<foreignObject>.
interface QROptions {
errorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H'; // default: 'M'
version?: number; // 1–40, default: auto
}Generates an SVG string without mounting to the DOM. Useful for server-side rendering, saving to a database, or copying to clipboard.
import { toSVGString } from '@ttsalpha/qrcode';
const svg = toSVGString({ value: 'https://example.com', size: 512 });
// "<svg role="img" ...>...</svg>"Renders the QR code to a data: URL via Canvas. Browser-only (requires Canvas API).
import { toDataURL } from '@ttsalpha/qrcode';
// PNG (default)
const png = await toDataURL({ value: 'https://example.com', size: 512 });
// JPEG with quality
const jpg = await toDataURL(
{ value: 'https://example.com', size: 512 },
{ format: 'jpeg', quality: 0.9 },
);
// Use as download link
const link = document.createElement('a');
link.href = await toDataURL({ value: 'https://example.com' });
link.download = 'qrcode.png';
link.click();| Option | Type | Default | Description |
|---|---|---|---|
format |
'png' | 'jpeg' |
'png' |
Output image format |
quality |
number (0–1) |
browser default | JPEG quality. Ignored for PNG |
Note: JPEG has no alpha channel. When
backgroundColoris'transparent', the background is automatically filled with white.
- QR versions 1–40, auto-selects the minimum version that fits the data
- Encoding modes: Numeric, Alphanumeric, Byte (UTF-8) — auto-selected
- Full Reed-Solomon error correction over GF(256)
- All 8 mask patterns evaluated with ISO 18004 penalty scoring
- All function patterns: finder, separator, timing, alignment, dark module, format info, version info
MIT © Son Tran