QR Code Generator — Free HTML CSS JS Snippet
QR Code Generator · Tools · Plain HTML, CSS & JS · Live preview
Copy & paste
Source Code
<div class="demo">
<div class="qr-card">
<label class="field">
<span>Text or URL</span>
<input type="text" class="qr-input" value="https://webdevpuneet.com" placeholder="Type something to encode..." />
</label>
<div class="row">
<label class="field small">
<span>Code colour</span>
<input type="color" class="qr-fg" value="#1f2937" />
</label>
<label class="field small">
<span>Background</span>
<input type="color" class="qr-bg" value="#ffffff" />
</label>
</div>
<div class="qr-preview">
<canvas class="qr-canvas"></canvas>
</div>
<button class="download-btn" type="button">Download PNG</button>
</div>
</div>.demo {
font-family: 'Segoe UI', system-ui, sans-serif;
display: flex;
justify-content: center;
padding: 28px;
background: #f1f5f9;
}
.qr-card {
width: 100%;
max-width: 340px;
background: #fff;
border-radius: 16px;
border: 1px solid #e2e8f0;
box-shadow: 0 14px 36px rgba(15,23,42,0.08);
padding: 20px;
display: flex;
flex-direction: column;
gap: 14px;
}
.field {
display: flex;
flex-direction: column;
gap: 6px;
font-size: 12px;
font-weight: 600;
color: #475569;
}
.field input[type="text"] {
font-size: 14px;
font-weight: 400;
padding: 9px 12px;
border-radius: 8px;
border: 1px solid #cbd5e1;
outline: none;
font-family: inherit;
}
.field input[type="text"]:focus {
border-color: #6366f1;
box-shadow: 0 0 0 3px rgba(99,102,241,0.15);
}
.row {
display: flex;
gap: 14px;
}
.field.small {
flex: 1;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.field.small input[type="color"] {
width: 38px;
height: 28px;
border: none;
border-radius: 6px;
cursor: pointer;
background: none;
}
.qr-preview {
display: flex;
justify-content: center;
align-items: center;
background: #f8fafc;
border: 1px dashed #cbd5e1;
border-radius: 12px;
padding: 16px;
min-height: 200px;
}
.qr-canvas {
border-radius: 8px;
max-width: 100%;
}
.download-btn {
border: none;
background: #4f46e5;
color: #fff;
font-size: 13px;
font-weight: 600;
padding: 10px 16px;
border-radius: 8px;
cursor: pointer;
transition: background 0.2s ease;
}
.download-btn:hover { background: #4338ca; }const input = document.querySelector('.qr-input');
const fg = document.querySelector('.qr-fg');
const bg = document.querySelector('.qr-bg');
const canvas = document.querySelector('.qr-canvas');
const downloadBtn = document.querySelector('.download-btn');
let timer = null;
function render() {
const text = input.value.trim() || ' ';
QRCode.toCanvas(canvas, text, {
width: 220,
margin: 1,
color: { dark: fg.value, light: bg.value },
}, (err) => {
if (err) console.error(err);
});
}
function scheduleRender() {
clearTimeout(timer);
timer = setTimeout(render, 200);
}
input.addEventListener('input', scheduleRender);
fg.addEventListener('input', render);
bg.addEventListener('input', render);
downloadBtn.addEventListener('click', () => {
const link = document.createElement('a');
link.download = 'qr-code.png';
link.href = canvas.toDataURL('image/png');
link.click();
});
render();Extend with AI
Take This Snippet Further With AI
The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.
What's included
Features
QRCode.toCanvas's color option directly, recolouring the entire matrix in real time as you dragcanvas.toDataURL("image/png") plus a programmatic <a download> click exports the finished code as a standalone image with no server involvedAbout this UI Snippet
How this QR code generator was built — qrcode.js, debounced rendering, and canvas export

This snippet recreates the "type a link, get a scannable code" widget you see on share pages, business-card tools, and Wi-Fi-login screens — every keystroke redraws a real, scannable QR code on canvas, with adjustable foreground/background colours and a one-click PNG download. Rather than computing QR matrices by hand (a genuinely fiddly bit of error-correction math), it loads the small, focused qrcode.js library from a CDN and wires it up to a live form with about 35 lines of glue code.
Why reach for a CDN library here
QR codes are not just a pattern of black and white squares — they encode data with Reed–Solomon error correction so a scanner can still read the code even if part of it is smudged, printed small, or partially obscured by a logo. Implementing that correctly from scratch is a project in itself, so this snippet pulls in [email protected] from jsDelivr and calls its single QRCode.toCanvas() method — the same "load a focused library, then build your UI around it" approach used by the Theme Palette Generator for colour math, just applied to a domain where hand-rolling the algorithm would be wasted effort.
Live rendering with a debounce
The text input fires QRCode.toCanvas(canvas, text, options, callback) on every keystroke, but redrawing on *every single character* would be wasteful and can visibly stutter on slower devices — so the snippet wraps the call in a scheduleRender() function that clears any pending setTimeout and queues a fresh one 200ms later. Type continuously and only the final pause triggers a render; the colour pickers call render() directly since dragging a colour wheel naturally produces fewer, more deliberate updates. This debounce pattern is a small but important detail any time you're rendering something non-trivial in response to rapid input events.
Live colour customization
Two native <input type="color"> swatches feed straight into QRCode.toCanvas's color: { dark, light } option — the library redraws the entire matrix in the chosen foreground and background colours on every input event, so the preview updates in real time as you drag the colour wheel. No extra canvas manipulation is needed; the library handles the recoloring as part of its normal render path.
Exporting the finished code
"Download PNG" reuses the same canvas.toDataURL('image/png') plus programmatic <a download> click pattern as the Signature Pad snippet — because QRCode.toCanvas draws onto a real <canvas> element, the resulting image is just standard canvas content, exportable with the browser's built-in encoding and no extra image-processing step.
Step by step
How to Use
- 1Load the qrcode.js library from a CDNAdd
https://cdn.jsdelivr.net/npm/[email protected]/build/qrcode.min.jsto the page — it exposes a globalQRCodeobject with atoCanvas()method that handles the encoding and error-correction math for you. - 2Build the form: text input + two colour pickersAdd a text
<input>for the content to encode and two<input type="color">swatches bound todark(foreground) andlight(background), plus a<canvas>to render into. - 3Render with QRCode.toCanvasCall
QRCode.toCanvas(canvas, text, { width, margin, color: { dark, light } }, callback)— the library draws the full QR matrix directly onto the canvas element you pass it. - 4Debounce text input, render colours immediatelyWrap the text-input handler in a
scheduleRender()that clears and resets asetTimeout(render, 200)so rapid typing only triggers one render per pause; callrender()directly from the colour inputs'inputevents. - 5Add PNG exportOn the download button, set a temporary
<a>'sdownloadattribute andhref = canvas.toDataURL("image/png"), then call.click()— the canvas content (the QR code) saves as a standard image file. - 6Render once on loadCall
render()immediately after wiring up the listeners so the canvas shows a live, scannable code with the default text and colours before the visitor types anything.
Real-world uses
Common Use Cases
WIFI: connection string and let the generator render a printable, on-brand code with custom colours that match your venue or packaging.scheduleRender() debounce is a reusable pattern for any input-driven preview — search-as-you-type, live markdown rendering (see the Markdown Live Preview snippet), or canvas-based tools that redraw on every keystroke.Got questions?
Frequently Asked Questions
A QR code is not just a grid of black and white squares — it encodes data using Reed–Solomon error correction so the code stays scannable even when partly damaged, small, or covered by a logo. Computing that matrix correctly is a non-trivial algorithm in its own right, so this snippet loads the small, focused qrcode.js library from a CDN and calls its toCanvas() method, which produces a fully spec-compliant, scannable code in one call.
Typing produces many rapid input events — re-rendering the QR matrix on every keystroke would be wasteful and can visibly stutter. scheduleRender() clears any pending setTimeout and queues a new 200ms-delayed render, so only the pause after typing triggers a redraw. Dragging a colour wheel, by contrast, naturally produces fewer and more deliberate change events, so the colour inputs call render() directly for instant visual feedback.
The two <input type="color"> swatches are passed straight into QRCode.toCanvas's color: { dark: fg.value, light: bg.value } option. The dark value colours the QR modules (the foreground pattern) and light colours the background — the library redraws the entire matrix in those colours on every input event, so the preview updates live as you pick.
Yes, as long as there is enough contrast between the foreground and background colours for a scanner's camera to distinguish the modules — very low-contrast combinations (e.g. two similar pastel shades) can make scanning unreliable on some devices. The size set via the width option does not affect scannability; it only changes how large the rendered canvas is.
Click "Download PNG" — it calls canvas.toDataURL("image/png") to get a base64-encoded image of the canvas, assigns it to a temporary <a download="qr-code.png"> link, and clicks it programmatically. The browser handles the save dialog, producing a standalone PNG file with no server round-trip.
Yes — the HTML, CSS, and JS on this page are free to copy and adapt anywhere, including commercial products. The qrcode.js library it loads from jsDelivr is published under the MIT license, so there are no usage restrictions or attribution requirements to worry about.
Yes. Use the export buttons on this page: JSX downloads a React component, Vue a Vue 3 SFC, Angular a standalone component, and Tailwind a utility-class version. In React, load the qrcode.js script inside useEffect and generate the code after the library resolves; in Vue use onMounted.