Building a Custom QR Code Generator with qrcode.js and JavaScript

236
0

Hello friends, today in this blog, we will learn how to build a custom QR code generator with qrcode.js and JavaScript. In our previous blog, we saw how to create a music player using HTML, CSS, and JavaScript. You can check my other javascript projects after reading this blog.

QR codes have become increasingly popular over the years due to their ability to store a large amount of information in a small space. They are widely used for various purposes, such as tracking inventory, sharing contact information, and making payments. However, creating custom QR codes tailored to specific needs and branding can be challenging.

This tutorial will show you how to build a custom QR code generator using qrcode.js and JavaScript. qrcode.js is a JavaScript library that allows you to generate QR codes quickly, while JavaScript is a versatile programming language that can be used to build web applications.

By the end of this tutorial, you will have a custom QR code generator that allows you to generate QR codes with customizations such as logos, colors, and background images. This will enable you to create QR codes that are not only functional but also visually appealing and in line with your brand’s image.

what is qrcode.js?

qrcode.js is a JavaScript library that makes it easy to generate QR codes. Before we can use qrcode.js to create our custom QR code generator, we need to install and set it up. There are a few ways to use it such as downloading local file, CDN link, and NPM. You can check its GitHub documentation here.

In this project, as you can see in the above image we have five buttons for generating different types of QR codes. We can create QR for any text or paragraph, URL, E-mail, Phone, or SMS. After filling in all the fields the QR will be generated. After generating QR we can download it.

Code of HTML, CSS, and JavaScript Files

Here’s the good news: you don’t have to write all the code of this project from scratch! I have created a GitHub repository that contains all the HTML, CSS, and JavaScript code needed to build the app. You can check it out and use it as a starting point for your own project.

NOTE:
You Can Check Live Demo of this project and download code and image files from here.

HTML CODE

<!DOCTYPE html>
<html lang="en">

<head>
    <!-- --------------------- Created By InCoder --------------------- -->
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>QR Code Generator - InCoderWeb</title>
    <link rel="stylesheet" href="main.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />
</head>

<body>
    <div class="QRMainContainer">
        <div class="title">QR Code Generator</div>
        <div class="typesOfQR">
            <button class="QRTypeBtn textBtn active" data-type="text"><i class="fa-solid fa-file-lines"></i> Free
                Text</button>
            <button class="QRTypeBtn urlBtn" data-type="url"><i class="fa-solid fa-link"></i> URL</button>
            <button class="QRTypeBtn emailBtn" data-type="email"><i class="fa-solid fa-at"></i> E-Mail</button>
            <button class="QRTypeBtn phoneBtn" data-type="phone"><i class="fa-solid fa-phone"></i> Phone</button>
            <button class="QRTypeBtn smsBtn" data-type="sms"><i class="fa-solid fa-comment-dots"></i> SMS</button>
        </div>
        <div class="inputFields">
            <div class="freeTextInput inputBox active">
                <textarea placeholder="Enter text to share" class="textareaTag"></textarea>
            </div>
            <div class="urlInput inputBox">
                <input placeholder="Enter URL" type="url" class="inputTag" />
                <p>Enter Link to open when scanned, e.g. https://example.com/</p>
            </div>
            <div class="emailInput inputBox">
                <p>It opens a new email compose draft when scanned. <b>Note: Fill All Fields in order to generate correct QR Code.</b></p>
                <input placeholder="Enter E-mail ID" type="email" class="inputTag" />
                <input placeholder="Enter E-mail Subject" type="text" class="inputTag" />
                <textarea placeholder="Enter Message" class="textareaTag"></textarea>
                <p style="float: right;" id="characterCount">20/1000</p>
            </div>
            <div class="phoneInput inputBox">
                <b>Note: In phone number field, first enter country Code and then enter your number.</b>
                <input style="margin-top: .5rem;" placeholder="Enter Phone Number" type="text" class="inputTag" />
            </div>
            <div class="smsInput inputBox">
                <b>Note: In phone number field, first enter country Code and then enter your number.</b>
                <input style="margin-top: .5rem;" placeholder="Enter Phone Number" type="text" class="inputTag" />
                <textarea placeholder="Enter Message" class="textareaTag"></textarea>
            </div>
        </div>
        <div class="QROutputWrapper">
            <p style="text-align: right!important; width: 100%;" id="demoText">Demo QR Code</p>
            <img alt="Demo QR Code" src="images/qr-code.png" id="demoQR" />
            <div id="qrCode"></div>
            <p id="demoInfo">Fill the fields to generate QR code.</p>
        </div>
        <button id="downloadBtn"><i class="fa-solid fa-download"></i> Download QR Code</button>
    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
    <script src="script.js"></script>
</body>

</html>

CSS CODE

@import url("https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap");
/* --------------------- Created By InCoder --------------------- */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Ubuntu", sans-serif;
}

body {
  display: flex;
  height: 100vh;
  align-items: center;
  justify-content: center;
  background-color: #c9580f;
}

input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  margin: 0;
}

.QRMainContainer {
  width: 35rem;
  padding: 1rem;
  margin: 0.6rem;
  transform: scale(.8);
  background: #fff;
  border-radius: 0.5rem;
}

.QRMainContainer .title {
  font-weight: 700;
  color: #000000e6;
  margin-bottom: 0.8rem;
  font-size: clamp(1.5rem, 3.5vw, 2.5rem);
}

.QRTypeBtn {
  border: none;
  padding: 0.5rem;
  cursor: pointer;
  color: #c9580f;
  font-size: 1.1rem;
  margin-right: 0.5rem;
  margin-bottom: 0.5rem;
  border-radius: 0.6rem;
  border: 0.2rem solid #c9580f;
  transition: all 0.3s ease-in-out;
}

.QRTypeBtn:hover,
.QRTypeBtn.active {
  color: #fff;
  background: #c9580f;
}

.inputFields {
  margin-top: 1rem;
}

.inputTag {
  width: 100%;
  height: 3.2rem;
  font-size: 1.3rem;
  margin-bottom: 1rem;
  padding: 0rem 0.5rem;
  border-radius: 0.5rem;
  border: 3px solid #00000042;
}

.inputTag:focus {
  outline: none;
  border: 3px solid #c9580f;
}

.textareaTag {
  width: 100%;
  height: 8rem;
  padding: 0.5rem;
  resize: vertical;
  font-size: 1.2rem;
  border-radius: 0.5rem;
  border: 3px solid #00000042;
}

.textareaTag:focus {
  outline: none;
  border: 3px solid #c9580f;
}

/* -------------------------- Free Text Section End -------------------------- */

.freeTextInput textarea {
  display: none;
}

.freeTextInput textarea::placeholder {
  font-size: 1.2rem;
}

.freeTextInput.active textarea {
  display: block;
}

/* -------------------------- Free Text Section End -------------------------- */

/* -------------------------- URL Section Start -------------------------- */

.urlInput {
  display: none;
}

.urlInput input {
  margin-bottom: 0.2rem !important;
}
.urlInput p {
  font-size: 0.9rem;
  padding-left: 0.2rem;
}

.urlInput.active {
  display: block;
}

/* -------------------------- URL Section End -------------------------- */

/* -------------------------- E-Mail Section Start -------------------------- */

.emailInput {
  display: none;
}

.emailInput.active {
  display: block;
}
.emailInput p {
  margin-bottom: 0.3rem;
}

/* -------------------------- E-Mail Section End -------------------------- */

/* -------------------------- Phone Section Start -------------------------- */

.phoneInput {
  display: none;
}

.phoneInput.active {
  display: block;
}

/* -------------------------- Phone Section End -------------------------- */

/* -------------------------- SMS Section Start -------------------------- */

.smsInput {
  display: none;
}

.smsInput.active {
  display: block;
}

/* -------------------------- SMS Section End -------------------------- */

.QROutputWrapper {
  display: flex;
  padding: 1rem;
  margin-top: 1.5rem;
  align-items: center;
  flex-direction: column;
  justify-content: center;
  border: 1px dashed #000000bd;
}

.QROutputWrapper img {
  width: 10rem;
  height: 10rem;
  margin-bottom: 0.5rem;
}

#downloadBtn {
  z-index: 1;
  border: 0px;
  width: 100%;
  color: #fff;
  display: none;
  cursor: pointer;
  overflow: hidden;
  margin-top: 1rem;
  font-size: 1.2rem;
  position: relative;
  border-radius: 6px;
  padding: 0.8rem 2rem;
  background: #c9580f;
  text-decoration: none;
  background-position: 5rem;
  text-transform: capitalize;
}

#downloadBtn::before {
  content: "";
  top: 0%;
  left: -100%;
  z-index: -1;
  width: 100%;
  height: 100%;
  color: #fff;
  position: absolute;
  transition: left 0.4s;
  background-color: #202020;
}

#downloadBtn:hover::before {
  left: 0%;
}

JAVASCRIPT CODE

// --------------------- Created By InCoder ---------------------
const QRTypeBtn = document.querySelectorAll(".QRTypeBtn")
oldQR = document.getElementById("qrCode")
demoQR = document.getElementById("demoQR")
inputBox = document.querySelectorAll('.inputBox')
inputTag = document.querySelectorAll('.inputTag')
textareaTag = document.querySelectorAll('.textareaTag')
textBtn = document.querySelector('.textBtn')
urlBtn = document.querySelector('.urlBtn')
emailBtn = document.querySelector('.emailBtn')
phoneBtn = document.querySelector('.phoneBtn')
smsBtn = document.querySelector('.smsBtn')

const toggleTab = (type) => {
    switch (type) {
        case "text":
            textBtn.classList.add('active')
            document.querySelector('.freeTextInput').classList.add('active')
            break;
        case "url":
            urlBtn.classList.add('active')
            document.querySelector('.urlInput').classList.add('active')
            break;
        case "email":
            emailBtn.classList.add('active')
            document.querySelector('.emailInput').classList.add('active')
            break;
        case "phone":
            phoneBtn.classList.add('active')
            document.querySelector('.phoneInput').classList.add('active')
            break;
        case "sms":
            smsBtn.classList.add('active')
            document.querySelector('.smsInput').classList.add('active')
            break;
    }
}

const downloadQRCode = (imageBase64) => {
    var a = document.createElement("a")
    a.href = imageBase64
    a.download = `QR Image ${Date.now()}.png`
    a.click()
}

QRTypeBtn.forEach((btn) => {
    btn.addEventListener('click', (e) => {
        QRTypeBtn.forEach((btn) => {
            if (btn.classList.contains('active')) {
                btn.classList.remove('active')
            }
        })
        inputBox.forEach((box) => {
            if (box.classList.contains('active')) {
                box.classList.remove('active')
            }
        })
        document.getElementById("demoText").style.display = 'block'
        document.getElementById("demoInfo").style.display = 'block'
        document.getElementById("downloadBtn").style.display = 'none'
        oldQR.innerHTML = ''
        demoQR.style.display = 'block'
        let type
        if (e.target.nodeName == "I") {
            type = e.target.parentElement.getAttribute('data-type')
        } else {
            type = e.target.getAttribute('data-type')
        }
        toggleTab(type)
    })
})

const generateQR = (text) => {
    demoQR.style.display = 'none'
    document.getElementById("demoText").style.display = 'none'
    document.getElementById("demoInfo").style.display = 'none'
    document.getElementById("downloadBtn").style.display = 'block'
    oldQR.innerHTML = ''

    let qrcode = new QRCode(document.getElementById("qrCode"), {
        text: text,
        width: 160,
        height: 160,
        colorDark: "#000",
        colorLight: "#fff",
        correctLevel: QRCode.CorrectLevel.H
    });
}

let emailData = {}
let smsData = {}

inputTag.forEach((tag) => {
    tag.addEventListener('keyup', (e) => {
        if (e.target.value == '') {
            document.getElementById("demoText").style.display = 'block'
            document.getElementById("demoInfo").style.display = 'block'
            document.getElementById("downloadBtn").style.display = 'none'
            oldQR.innerHTML = ''
            demoQR.style.display = 'block'
        } else {
            if (document.querySelector('.emailInput').classList.contains('active')) {
                Object.assign(emailData, {
                    email: document.querySelectorAll('.emailInput input')[0].value,
                    emailSubject: document.querySelectorAll('.emailInput input')[1].value
                })
            } else if (document.querySelector('.phoneInput').classList.contains('active')) {
                generateQR(`tel:${document.querySelector('.phoneInput input').value}`)
            } else if (document.querySelector('.smsInput').classList.contains('active')) {
                Object.assign(smsData, {
                    phone: document.querySelector('.smsInput input').value
                })
            } else {
                generateQR(e.target.value)
            }
        }
    })
})

textareaTag.forEach((tag) => {
    tag.addEventListener('keyup', (e) => {
        if (e.target.value == '') {
            document.getElementById("demoText").style.display = 'block'
            document.getElementById("demoInfo").style.display = 'block'
            document.getElementById("downloadBtn").style.display = 'none'
            oldQR.innerHTML = ''
            demoQR.style.display = 'block'
        } else {
            if (document.querySelector('.emailInput').classList.contains('active')) {
                Object.assign(emailData, { emailMessage: document.querySelector('.emailInput textarea').value })
                let emailQRData = `mailto:${emailData.email}?body=${emailData.emailMessage}&subject=${emailData.emailSubject}`
                if (emailData.emailSubject != undefined || emailData.email != undefined) {
                    generateQR(emailQRData)
                } else {
                    alert("First fill Email ID and Subject then fill this field. Otherwise QR Code will not be generated.")
                }
            } else if (document.querySelector('.smsInput').classList.contains('active')) {
                Object.assign(smsData, {
                    message: document.querySelector('.smsInput textarea').value
                })
                let smsQRData = `SMSTO:${smsData.phone}:${smsData.message}`
                generateQR(smsQRData)
            } else {
                generateQR(e.target.value)
            }
        }
    })
})

downloadBtn.addEventListener('click', () => {
    let imageSRC = document.getElementById("qrCode").querySelector('img').getAttribute('src')
    downloadQRCode(imageSRC)
})
Ashutosh Tiwari
WRITTEN BY

Ashutosh Tiwari

Hey there, I'm Ashutosh Tiwari AKA InCoder and I'm a front-end and back-end developer. I create blogs, and I love helping people through my knowledgeable content. My content is all about coding and front-end design. When I'm not creating content, you can find me reading books and listening to podcasts. I set up this Buy Me a Coffee account to help support my work, as creating content takes time and effort. Every contribution helps me continue doing what I love and improving the quality of my content. Thank you so much for your support and for being a part of my journey!

Newsletter

Loading