There are numerous CAPTCHA services available which we often use to secure our websites from spam and bots. The most popular ones include Google’s reCAPTCHA, Cloudfare’s Turnstile, hCpatcha, etc.
However, most of these services often require a backend server to perform validations. When we run a small website without much complexity, using these services might look like overkill.
While these services are excellent at providing security, we can create our own simplified version of CAPTCHA.
In this tutorial, we’re going to see how we can create a custom CAPTCHA generator using vanilla JavaScript in Vue.js.
The idea is to have a number of characters displayed in a row (say 5). We then change the size and rotation of each of the characters with a random value. It creates some randomness and visual challenge:
Here’s the example code:
<template>
<div id="app">
<h2></h2>
<div class="np-captcha-container">
<div class="np-captcha" v-if="captcha && captcha.length">
<div
v-for="(c, i) in captcha"
:key="i"
:style="{
fontSize: getFontSize() + 'px',
fontWeight: 800,
transform: 'rotate(' + getRotationAngle() + 'deg)',
}"
class="np-captcha-character"
>
{{ c }}
</div>
</div>
</div>
<button @click="createCaptcha" class="np-button">Generate new</button>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
captchaLength: 5,
captcha: [],
};
},
mounted() {
this.createCaptcha();
},
methods: {
createCaptcha() {
let tempCaptcha = "";
for (let i = 0; i < this.captchaLength; i++) {
tempCaptcha += this.getRandomCharacter();
}
this.captcha = tempCaptcha.split("");
},
getRandomCharacter() {
const symbols = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
const randomNumber = Math.floor(Math.random() * 36);
return symbols[randomNumber];
},
getFontSize() {
const fontVariations = [14, 20, 30, 36, 40];
return fontVariations[Math.floor(Math.random() * 5)];
},
getRotationAngle() {
const rotationVariations = [5, 10, 20, 25, -5, -10, -20, -25];
return rotationVariations[Math.floor(Math.random() * 8)];
},
},
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #000000;
margin-top: 60px;
}
.np-captcha-container {
background: #eee;
width: 300px;
margin: 0 auto;
margin-bottom: 20px;
}
.np-captcha {
font-size: 24px;
}
.np-button {
padding: 6px 10px;
background: #fff;
border: 1px solid #eee;
border-radius: 6px;
font-size: 16px;
}
.np-captcha-character {
display: inline-block;
letter-spacing: 14px;
}
</style>
Code language: HTML, XML (xml)
In the above code, through lines 10-12, we’re setting the transform property with a dynamic rotate() value. We get it’s value from the getRotationAngle() method. We’re also setting the font size value from the getFontSize() method. Here’s what each of the methods do in our code:
- createCaptcha: It creates a string of random characters between A-Z and 0-9 of the mentioned length (captchaLength).
- getRandomCharacter: It returns a random character between A-Z and 0-9.
- getFontSize: It returns a font value from a set of predefined font sizes. We can add more values here for greater variation.
- getRotationAngel: It returns an angle in degree from a set of predefined angle values.
Here’s how the above code would look in action:
You can find a working version of the above code from my repo links below: