Hi All,
Demo here: https://matt7933.softr.app/qr-code-generator
Note that the QR Code color, the QR code background-color, the QR code file type (image as Jpeg or PNG) and the QR code size are customizable.
It should also be responsive (
).
Below is the full code. To be inserted in a custom code block
Made on top of qrcode.js library
Just Copy-Paste it
<html>
<head>
<style>
:root {
--container-bg-color: #ffffff;
--container-border-radius: 8px;
--box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.1);
--title-font-size: 20px;
--title-color: #333;
--input-font-size: 16px;
--input-border-color: #ccc;
--input-focus-border-color: #007bff;
--input-border-radius: 4px;
--button-bg-color: #007BFF;
--button-hover-bg-color: #0056b3;
--button-text-color: #fff;
--button-font-size: 16px;
--button-border-radius: 6px;
--label-font-size: 14px;
--label-color: #333;
--customization-label-font-size: 16px;
--customization-label-color: #333;
--color-group-gap: 16px;
--display-qr-size: 150px;
--download-qr-size: 300;
--placeholder-color: #aaaaaa;
--placeholder-font-size: 15px;
--placeholder-font-weight: 400;
}
.qr-generator-wrapper {
display: flex;
justify-content: center;
align-items: flex-start;
padding: 20px;
margin: 0 auto;
max-width: 320px;
}
.qr-generator-container {
text-align: left;
padding: 20px;
width: 100%;
background-color: var(--container-bg-color);
box-shadow: var(--box-shadow);
border-radius: var(--container-border-radius);
display: flex;
flex-direction: column;
gap: 20px;
}
.qr-generator-container h1 {
font-size: var(--title-font-size);
margin-bottom: 20px;
color: var(--title-color);
order: -1;
}
.qr-code-section {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
order: 2;
}
.controls-section {
width: 100%;
order: 1;
}
.input-group {
display: flex;
gap: 8px;
margin-bottom: 20px;
}
.input-group input[type="text"] {
flex: 1;
padding: 10px;
font-size: var(--input-font-size);
border: 1px solid var(--input-border-color);
border-radius: var(--input-border-radius);
outline: none;
transition: border-color 0.2s ease;
}
.input-group input[type="text"]:focus {
border-color: var(--input-focus-border-color);
}
.customization-label {
font-size: var(--customization-label-font-size);
color: var(--customization-label-color);
margin-bottom: 10px;
font-weight: 500;
text-align: left;
}
.color-group {
display: flex;
flex-direction: column;
gap: var(--color-group-gap);
margin-bottom: 20px;
}
.color-group label {
display: flex;
flex-direction: column;
font-size: var(--label-font-size);
font-weight: 500;
color: var(--label-color);
}
.color-group input[type="color"],
.color-group input[type="number"],
.color-group select {
width: 100%;
height: 40px;
border: 1px solid var(--input-border-color);
border-radius: var(--input-border-radius);
padding: 8px;
font-size: var(--input-font-size);
outline: none;
transition: border-color 0.2s ease;
}
#qrcode {
margin-top: 20px;
width: var(--display-qr-size);
height: var(--display-qr-size);
position: relative;
display: inline-block;
}
.placeholder-text {
color: var(--placeholder-color);
font-size: var(--placeholder-font-size);
font-weight: var(--placeholder-font-weight);
margin-top: 20px;
display: block;
text-align: center;
}
.message {
margin-top: 10px;
color: green;
display: none;
font-size: 14px;
font-weight: 500;
text-align: center;
}
.copy-button {
background-color: #d3e8ff;
border: 1px solid #d3e8ff;
border-radius: 6px;
margin-top: 10px;
padding: 4px 8px;
display: none;
transition: background-color 0.4s ease;
}
.copy-button:hover {
background-color: #007bff;
color: #fff;
}
.button-container {
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
margin-top: 20px;
width: 100%;
}
.generate-button {
background-color: var(--button-bg-color);
color: var(--button-text-color);
font-size: var(--button-font-size);
border-radius: var(--button-border-radius);
border: none;
padding: 10px 20px;
cursor: pointer;
transition: all 0.3s ease;
width: 100%;
}
.generate-button:disabled {
background-color: #cccccc !important;
cursor: not-allowed;
opacity: 0.7;
}
.generate-button:not(:disabled):hover {
background-color: var(--button-hover-bg-color);
}
.loading-spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid var(--button-bg-color);
border-radius: 50%;
width: 20px;
height: 20px;
animation: spin 0.8s linear infinite;
display: none;
margin-left: 10px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.download-button {
background-color: var(--button-bg-color);
color: var(--button-text-color);
font-size: 14px;
font-weight: 500;
border-radius: var(--button-border-radius);
border: none;
padding: 6px 12px;
cursor: pointer;
transition: background-color 0.3s;
margin-top: 1px;
display: none;
width: 100%;
}
.download-button:hover {
background-color: var(--button-hover-bg-color);
}
/* Desktop styles */
@media (min-width: 768px) {
.qr-generator-wrapper {
max-width: 600px;
}
.qr-generator-container {
display: grid;
grid-template-columns: auto 1fr;
}
.qr-code-section {
width: var(--display-qr-size);
order: 0;
}
.controls-section {
order: 0;
}
.color-group {
display: flex;
flex-direction: row;
}
.generate-button,
.download-button {
width: auto;
}
.placeholder-text {
margin-top: 80px;
}
}
@media (min-width: 1024px) {
.qr-generator-wrapper {
max-width: 780px;
}
}
</style>
</head>
<body>
<div class="qr-generator-wrapper">
<div class="qr-generator-container">
<div class="qr-code-section">
<span class="placeholder-text" id="placeholder-text">The QR code will appear here.</span>
<div id="qrcode"></div>
<div class="button-container">
<button id="download-button" class="download-button" onclick="downloadQRCode()">Instant Download</button>
</div>
<div class="message" id="copy-message">Downloaded!</div>
</div>
<div class="controls-section">
<h1>QR Code Generator</h1>
<div class="input-group">
<input type="text" id="text-input" placeholder="Enter the desired URL" oninput="validateInput()">
</div>
<div class="customization-label">Customization:</div>
<div class="color-group">
<label>
QR Code Color
<input type="color" id="qr-color" value="#000000">
</label>
<label>
Background Color
<input type="color" id="bg-color" value="#ffffff">
</label>
<label>
QR Code Size (px)
<input type="number" id="qr-size" value="300" min="100" max="1600">
</label>
<label>
Download Format
<select id="qr-format">
<option value="jpeg">JPEG</option>
<option value="png">PNG</option>
</select>
</label>
</div>
<button id="generate-button" class="generate-button" onclick="handleGenerateQRCode()" disabled>Generate</button>
<div class="loading-spinner" id="loading-spinner"></div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
<script>
let isFirstGeneration = true;
function validateInput() {
const input = document.getElementById('text-input');
const generateButton = document.getElementById('generate-button');
generateButton.disabled = !input.value.trim();
}
document.addEventListener('DOMContentLoaded', validateInput);
function handleGenerateQRCode() {
const generateButton = document.getElementById("generate-button");
const loadingSpinner = document.getElementById("loading-spinner");
const downloadButton = document.getElementById("download-button");
generateButton.disabled = true;
loadingSpinner.style.display = "inline-block";
if (isFirstGeneration) {
generateButton.textContent = "Re-Generate";
isFirstGeneration = false;
}
setTimeout(() => {
generateQRCode();
validateInput(); // Re-validate input after generation
loadingSpinner.style.display = "none";
downloadButton.style.display = "block";
}, 1000);
}
function generateQRCode() {
const input = document.getElementById("text-input").value;
const qrCodeContainer = document.getElementById("qrcode");
const qrColor = document.getElementById("qr-color").value;
const bgColor = document.getElementById("bg-color").value;
// Clear previous QR code
qrCodeContainer.innerHTML = "";
const qrcode = new QRCode(qrCodeContainer, {
text: input,
width: 150,
height: 150,
colorDark: qrColor,
colorLight: bgColor,
});
const placeholderText = document.getElementById("placeholder-text");
placeholderText.style.display = "none";
}
function downloadQRCode() {
const qrCodeContainer = document.getElementById("qrcode");
const qrCodeCanvas = qrCodeContainer.querySelector("canvas");
const qrSize = parseInt(document.getElementById("qr-size").value) || 300;
const format = document.getElementById("qr-format").value;
if (!qrCodeCanvas) {
alert("Please generate a QR code before downloading.");
return;
}
const downloadQRCodeContainer = document.createElement("div");
const downloadQRCode = new QRCode(downloadQRCodeContainer, {
text: document.getElementById("text-input").value,
width: qrSize,
height: qrSize,
colorDark: document.getElementById("qr-color").value,
colorLight: document.getElementById("bg-color").value,
});
const downloadCanvas = downloadQRCodeContainer.querySelector("canvas");
if (downloadCanvas) {
const tempCanvas = document.createElement("canvas");
const ctx = tempCanvas.getContext("2d");
tempCanvas.width = qrSize;
tempCanvas.height = qrSize;
// Fill background (important for JPEG format)
ctx.fillStyle = document.getElementById("bg-color").value;
ctx.fillRect(0, 0, qrSize, qrSize);
ctx.drawImage(downloadCanvas, 0, 0, qrSize, qrSize);
const link = document.createElement("a");
const mimeType = format === 'jpeg' ? 'image/jpeg' : 'image/png';
const fileExtension = format === 'jpeg' ? 'jpg' : 'png';
const dataURL = format === 'jpeg'
? tempCanvas.toDataURL(mimeType, 0.9)
: tempCanvas.toDataURL(mimeType);
link.href = dataURL;
link.download = `qrcode.${fileExtension}`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
tempCanvas.remove();
downloadQRCodeContainer.remove();
}
const copyMessage = document.getElementById("copy-message");
copyMessage.style.display = "block";
setTimeout(() => {
copyMessage.style.display = "none";
}, 3000);
}
</script>
</body>
</html>