Generate QR Code for Social Media Profiles

Ifeoma Imoh

QR (quick response) codes are a popular type of two-dimensional or matrix barcode that allows you to easily encode information in the form of machine-readable images. These images can be used anywhere, from websites and mobile apps to banners, brochures, flyers, and business cards. Its popularity and effectiveness can be attributed to several factors, including the ease with which it can be scanned from any angle with a simple camera the high level of data integrity it provides even when parts of the QR Code are damaged or dirty.

The widespread use of QR codes has resulted in the development of several free and paid platforms for generating and scanning them. In this article, we will build a QR code generator that will encode alphanumeric data representing social media links. After that, we will add two additional features. The first is the ability to download the image locally. The second is to upload the resulting image to Cloudinary and receive a shareable URL that can be copied to the clipboard. This should be fun!

Here is a link to the demo on CodeSandbox.

Project Setup

Run this command in your terminal to create a simple React application:

1npx create-react-app qr-code-generator

Next, run the following command in your terminal to install the dependencies we'll need for this project:

1npm i qrcode.react react-dropzone axios

The qrcode.react module will generate the QR code. The react-dropzone module will be used to add Drag and drop functionality for the images embedded on the QR code, while the **axios** module will be the HTTP client.

We'll also need to create a separate component (file picker) to handle the drag-and-drop for the images that will be embedded in our QR code. Run the following command at the root of your project to create a folder named components and a file inside called ImagePicker.js:

1mkdir components
2 cd components
3 touch ImagePicker.js

Render the Qr Code

Add the following to your App.js file:

1import './styles.css';
2 import { useState } from 'react';
3 import QrCode from 'qrcode.react';
4 export default function App() {
5 const [input, setInput] = useState('');
6 const uploadToCloudinary = async () => {};
7 const downloadImage = async () => {};
8 return (
9 <main className="App">
10 <div className="form_group norm container">
11 <label>Add link to social media profile</label>
12 <input
13 type="url"
14 value={input}
15 onChange={(e) => setInput(e.target.value)}
16 />
17 </div>
18 {input && (
19 <>
20 <div>
21 <QrCode value={input} size={400} level="M" includeMargin />
22 </div>
23 </>
24 )}
25 </main>
26 );
27 }

In this component, we begin with some CSS, then some React hooks, and finally the QrCode component. We define a state variable called input in our App component, which will hold the URL of a random social media profile; this is followed by two other functions, downloadImage and uploadToCloudinary, which we will discuss later. Our App component renders several things; the first is an input field that updates the state variable with data provided by the user. We also conditionally render the QrCode component based on the availability of the user input, and it accepts the following props:

  • value: the data that would be encoded in the QR code; this is fed the string stored in our input state variable.
  • size: this number would represent the dimensions of the rendered image holding the QR code.
  • level: the level prop represents the error correction level used. The value can be either low(“L”), medium(“M”), Quartile(“Q”), or high (“H”). Each value represents the error correction level used when generating the QR code. Higher values indicate better error correction. This would mean more data can be recovered even if the QR code gets damaged.
  • includeMargin: it accepts a boolean value, which we set to true. This would allow some extra space to surround the generated symbol. This area is known as the silent zone in QR Code terminology because it helps the scanner identify where the barcode begins and ends.

With this in place, you can run the application using the following command:

1npm start

In the running application, You should be able to add some text to the input field and see the resulting QR code generated.

Embed Logo in the QR Code

While plain QR code symbols are sufficient to decode any encoded information contained in them, for business and marketing needs which constitute one of the primary use for these symbols, adding a logo on your QR code provides you with several advantages. It demonstrates, aids in promoting your brand's identity and awareness, and so on.

To embed images in our QR code, we will first create an image picker component that will be used to get our images. We will then use this component in our App.js file to select files and add them to the QR code.

Add the following to your ImagePicker.js file:

1import { useDropzone } from 'react-dropzone';
2 const fileToB64 = (file) =>
3 new Promise((res, rej) => {
4 const fileReader = new FileReader();
5 fileReader.onload = () => res(fileReader.result);
6 fileReader.onerror = () => rej(fileReader.error);
7 fileReader.readAsDataURL(file);
8 });
9 export default function ImagePicker({ handleImageSelect, children }) {
10 const { getInputProps, getRootProps } = useDropzone({
11 maxFiles: 1,
12 accept: 'image/*',
13 onDrop: async (arrayOfFiles) => {
14 const b64URL = await fileToB64(arrayOfFiles[0]);
15 handleImageSelect(b64URL);
16 },
17 });
18 return (
19 <>
20 <div {...getRootProps({ className: 'form_group' })}>
21 <input {...getInputProps()} />
22 <label className={`bl`}>Drag files to add image to QR code</label>
23 {children}
24 </div>
25 </>
26 );
27 }

In this file, we start by bringing in the useDropzone hook provided by the react-dropzone module. Next, we define a helper function called fileToB64, which uses the FileReader API to return the Data URI of a Blob that gets passed as input.

Next, we define the ImagePicker component, which accepts two props; the first is a function called handleImageSelect which would be used to feed the selected files to the parent component. Because we will use the ImagePicker component as a wrapper for other components, it also accepts the children prop. In the component body, we configure the options we want for the Dropzone by calling useDropzone and passing it an object representing the preferences we want. Here, we choose only to accept a single file which must be an image. We also define a handling function for the onDrop event that would fire whenever our Dropzone receives a file. It gets the file, converts it to a data URI and feeds it to the parent component using the handleImageSelect prop.

The call to useDropzone returns an object containing the Dropzone state, and we extracted these three things from it:

  • getRootProps: When called, this function would return an object representing the props for the Dropzone container, which can be any HTML element.
  • getInputProps: this function holds the props for the input field, acting as the Decoy file picker for situations where the user decides to click on the Dropzone to pick files from their computer instead.

Based on the information above, this component renders some JSX, including the children prop it receives and an input element. They are nested within the Dropzone with the required props passed to the Dropzone and input element, respectively.

Next, let's use this component in our App.js file:

1import ImagePicker from './components/ImagePicker';

Next, let's create a variable that'll hold the content of our image.

1//...
2 export default function App() {
3 const [input, setInput] = useState('');
4 const [image, setImage] = useState('');
5 //...

Finally, we update the return statement of our App component like so.

1return (
2 <main className="App">
3 <div className="form_group norm container">
4 <label>link to social media profile</label>
5 <input
6 type="url"
7 value={input}
8 onChange={(e) => setInput(e.target.value)}
9 />
10 </div>
11 {input && (
12 <>
13 <section className="dnd_con">
14 <ImagePicker
15 handleImageSelect={(file) => {
16 setImage(file);
17 }}
18 >
19 <QrCode
20 value={input}
21 size={400}
22 imageSettings={
23 image
24 ? {
25 src: image,
26 excavate: true,
27 width: 82,
28 height: 82,
29 }
30 : {}
31 }
32 level="M"
33 includeMargin
34 />
35 </ImagePicker>
36 </section>
37 </>
38 )}
39 </main>
40 );

In the return statement above, we used the ImagePicker component to wrap the QrCode component. ImagePicker accepts a function it uses to store the selected file in state. The QrCode component accepts an ImageSettings prop that holds an object defining the settings we want for the image that will be embedded. By default, the rendered image will be placed in the center, but you can also specify the coordinates if you want. In our case, we will go with the default coordinates.

If you run your application now, you should be able to drag and drop images, as seen below.

Download QR Code

Update the downloadImage function in the App component like so:

1const downloadImage = async (e) => {
2 const canvas = document.querySelector('canvas');
3 const imageDataURI = canvas.toDataURL('png', 1.0);
4 const blob = await (await fetch(imageDataURI)).blob();
5 const URL = window.URL.createObjectURL(blob);
6 const el = document.createElement('a');
7 el.href = URL;
8 el.download = 'mydummyfile.png';
9 el.click();
10 window.URL.revokeObjectURL(URL);
11 };

This function starts by getting the canvas element in the DOM that renders the QR code and converts its contents to an image in the form of a Data URI. To make the Data URI downloadable, first, we transform it into a blob. Next, using the createObjectURL function, we create a string that references that blob in memory. This string is then passed as the href attribute to the anchor tag we created programmatically.

To download the blob, we specified the download attribute on the anchor tag. Next, we click the anchor tag programmatically to download the image. The call to window.URL.revokeObjectURL(URL) clears the blobs reference string to avoid memory leaks. Now, let's update the return statement of our App component with a button that triggers the dowloadImage function.

1return (
2 <main className="App">
3 <div className="form_group norm container">
4 <label>Add link to social media profile</label>
5 <input
6 type="url"
7 value={input}
8 onChange={(e) => setInput(e.target.value)}
9 />
10 </div>
11 {input && (
12 <>
13 //...
14 <section className="btn_con">
15 <button onClick={downloadImage}> download image</button>
16 </section>
17 </>
18 )}
19 </main>
20 );

Generate QR Code Link

In this section, we will make use of the Cloudinary to store and manage media assets. We need to create an account to store and manage media using Cloudinary. In the account details section on your dashboard, you should see your Credentials, as shown below.

We will be sending images to Cloudinary via unsigned POST requests for this tutorial. To do this, we need our account cloud name and an unsigned upload preset. Specify a name for the upload preset and set the signing mode to unsigned; this will be sufficient for our app.

Upload Logic

Before updating the uploadToCloudinary function in the App.js file, we need to create a state to keep track of the loading state for uploading.

1export default function App() {
2 //... other state variables
3 const [loading, setLoading] = useState(false);

Now update the contents of the uploadToCloudinary function to match the following:

1const uploadAndGenSharableURL = async () => {
2 const canvas = document.querySelector('canvas');
3 const imageDataURI = await canvas.toDataURL('png', 1.0);
4 const cloudname = 'INSERT-CLOUDNAME-HERE';
5 const upload_preset = 'INSERT-NAME-OF-UPLOAD-PRESET-HERE';
6 try {
7 setLoading(true);
8 let res = await axios.post(
9 `https://api.cloudinary.com/v1_1/${cloudname}/image/upload`,
10 {
11 file: imageDataURI,
12 upload_preset,
13 }
14 );
15 const { url } = res.data;
16 await navigator.clipboard.writeText(url);
17 alert('COPIED TO CLIPBOARD');
18 } catch (error) {
19 console.log(error.message);
20 } finally {
21 setLoading(false);
22 }
23 };

In this function, we start by getting the Data URI from the canvas element that renders the QR code. Next, we define variables to store our cloud name and upload preset. After that, we attempt to upload the file by hitting the image upload Cloudinary endpoint and passing the request body, which holds the two compulsory fields when doing unsigned uploads. The file key contains the Data URI of our QR code, and the upload_preset key holds the string representing the upload preset we created earlier.

If the API call is successful, we get a lot of things from the returned data, but what we are interested in is the url key that holds the URL pointing to the image on our Cloudinary account. Using the clipboard.writeText method, we copy the URL to the clipboard and notify the user. If the API call fails, we simply display an error message.

Now, let’s update our UI to include a button to trigger the uploadToCloudinary.

1return (
2 <main className="App">
3 //...
4
5 {input && (
6
7 //...
8 <section className="btn_con">
9 <button onClick={downloadImage}> download image</button>
10 <button onClick={uploadToCloudinary}>
11 {loading ? 'processing...' : 'copy QR code link'}
12 </button>
13 </section>
14 </>
15 )}
16 </main>
17 );
18 }

If we run our app now, we should be able to generate the QR codes with images embedded in them, download the resulting symbol, and get a sharable URL. You can also head over to the media gallery section of your Cloudinary dashboard to see the QR code image, as seen below.

Find the complete project here on GitHub.

Conclusion

In this article, we looked at how to build a QR code generator that encodes alphanumeric data representing social media links. This knowledge gives us a decent head start to explore the potential of this technology in future applications.

Resources you may find helpful:

Ifeoma Imoh

Software Developer

Ifeoma is a software developer and technical content creator in love with all things JavaScript.