Building a Password Generator App with Next.js
Day 10: Password Generator — 30 Days of 30 Projects Challenge
Hey everyone, I hope you’re all doing well and enjoying your coding journey, Am I right? By the way, today marks the tenth day of the 30-day of 30-projects challenge. Our 10th project will be creating a mini Next.js application — a password generator. Please make sure to clap and comment on this blog post. It motivates me to create more amazing content like this, Let’s get started straight away.
Overview of the Mini Next.js Application
Our Password Generator application allows users to:
- Input for password length and character types (letters, numbers, symbols)
- Generate and display the password
- Copy password to clipboard
Tech-Stack Used:
- Next.js: A React framework for building full-stack web applications.
- React: A JavaScript library for building user interfaces.
- Tailwind CSS: A utility-first CSS framework for styling.
- Shadcn UI: Beautifully designed tailwindcss components that you can copy and paste into your application.
- Vercel: For deploying the Nextjs web application.
Initialize a Nextjs project
Start by following this guide to set up the new project.
- Go to the “components” folder.
- Create a new file named “
password-generator.tsx
”. - This file will manage the entire functionality of the project.
We will go through the code step-by-step to make it easy to understand.
Component Breakdown
Import Statements
"use client";
import { useState, ChangeEvent } from "react";
import {
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
} from "@/components/ui/card";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Checkbox, CheckedState } from "@/components/ui/checkbox";
import { Button } from "@/components/ui/button"
- Enables client-side rendering.
- Imports necessary hooks and custom components.
State Hooks
const [length, setLength] = useState<number>(16);
const [includeUppercase, setIncludeUppercase] = useState<boolean>(true);
const [includeLowercase, setIncludeLowercase] = useState<boolean>(true);
const [includeNumbers, setIncludeNumbers] = useState<boolean>(true);
const [includeSymbols, setIncludeSymbols] = useState<boolean>(true);
const [password, setPassword] = useState<string>("");
length
: Stores the desired length of the password, initialized to 16.includeUppercase
: Indicates whether to include uppercase letters in the password, storing a boolean value initialized totrue
.includeLowercase
: Indicates whether to include lowercase letters in the password, storing a boolean value initialized totrue
.includeNumbers
: Indicates whether to include numbers in the password, storing a boolean value initialized totrue
.includeSymbols
: Indicates whether to include symbols in the password, storing a boolean value initialized totrue
.password
: Stores the generated password as a string.
Event Handlers
const handleLengthChange = (e: ChangeEvent<HTMLInputElement>): void => {
setLength(Number(e.target.value));
};
const handleCheckboxChange =
(setter: (value: boolean) => void) =>
(checked: CheckedState): void => {
if (typeof checked === "boolean") {
setter(checked);
}
};
handleLengthChange
Function: Updates thelength
state with the numeric value from the input field whenever it changes.handleCheckboxChange
Function: Returns a function that updates the respective state for checkboxes, ensuring the state is updated only if thechecked
value is a boolean.
Purpose:
handleLengthChange
: Ensures that the password length state is kept up to date based on user input.handleCheckboxChange
: Provides a reusable handler for updating the boolean state of various checkboxes, such as those for including uppercase letters, lowercase letters, numbers, and symbols in the password.
Password Generation Function
const generatePassword = (): void => {
const uppercaseChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const lowercaseChars = "abcdefghijklmnopqrstuvwxyz";
const numberChars = "0123456789";
const symbolChars = "!@#$%^&*()_+[]{}|;:,.<>?";
let allChars = "";
if (includeUppercase) allChars += uppercaseChars;
if (includeLowercase) allChars += lowercaseChars;
if (includeNumbers) allChars += numberChars;
if (includeSymbols) allChars += symbolChars;
if (allChars === "") {
alert("Please select at least one character type.");
return;
}
let generatedPassword = "";
for (let i = 0; i < length; i++) {
const randomIndex = Math.floor(Math.random() * allChars.length);
generatedPassword += allChars[randomIndex];
}
setPassword(generatedPassword);
};
- Character Sets: Defines strings containing uppercase letters, lowercase letters, numbers, and symbols.
- Character Pool: Constructs a pool of characters (
allChars
) based on the selected options (includeUppercase
,includeLowercase
,includeNumbers
,includeSymbols
). Alerts the user if no character types are selected. - Password Generation: Randomly selects characters from
allChars
to construct the password of the desiredlength
and updates thepassword
state with the generated password.
Clipboard Copy Function
const copyToClipboard = (): void => {
navigator.clipboard.writeText(password).then(
() => {
alert("Password copied to clipboard!");
},
(err) => {
alert("Failed to copy password to clipboard.");
}
);
};
copyToClipboard
Function: Copies the generated password to the clipboard using thenavigator.clipboard.writeText
method.- Success Handling: Alerts the user with a message “Password copied to clipboard!” if the copy operation is successful.
- Error Handling: Alerts the user with a message “Failed to copy password to clipboard.” if the copy operation fails.
JSX Return Statement
return (
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-100 dark:bg-gray-900">
<Card className="w-full max-w-md p-6 bg-white dark:bg-gray-800 shadow-lg rounded-lg">
<div className="mx-auto max-w-md space-y-6">
<div className="space-y-2 text-center">
<h1 className="text-3xl font-bold">Password Generator</h1>
<p className="text-gray-500 dark:text-gray-400">
Create a secure password with just a few clicks.
</p>
</div>
<div className="space-y-4">
<div className="space-y-2">
<Label htmlFor="length">Password Length</Label>
<Input
id="length"
type="number"
min="8"
max="32"
value={length}
onChange={handleLengthChange}
className="w-full"
/>
</div>
<div className="space-y-2">
<Label>Include:</Label>
<div className="flex items-center space-x-2">
<Checkbox
id="uppercase"
checked={includeUppercase}
onCheckedChange={handleCheckboxChange(setIncludeUppercase)}
/>
<Label htmlFor="uppercase">Uppercase Letters</Label>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="lowercase"
checked={includeLowercase}
onCheckedChange={handleCheckboxChange(setIncludeLowercase)}
/>
<Label htmlFor="lowercase">Lowercase Letters</Label>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="numbers"
checked={includeNumbers}
onCheckedChange={handleCheckboxChange(setIncludeNumbers)}
/>
<Label htmlFor="numbers">Numbers</Label>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="symbols"
checked={includeSymbols}
onCheckedChange={handleCheckboxChange(setIncludeSymbols)}
/>
<Label htmlFor="symbols">Symbols</Label>
</div>
</div>
<Button type="button" className="w-full" onClick={generatePassword}>
Generate Password
</Button>
<div className="space-y-2">
<Label htmlFor="password">Generated Password</Label>
<div className="flex items-center space-x-2">
<Input
id="password"
type="text"
value={password}
readOnly
className="flex-1"
/>
<Button type="button" onClick={copyToClipboard}>
Copy to Clipboard
</Button>
</div>
</div>
</div>
</div>
</Card>
</div>
);
- Container Div: Centers the password generator UI on the screen using flexbox, with a background that adapts to light and dark themes, ensuring the layout takes up at least the full height of the viewport.
- Card Component: Encapsulates the generator content with padding, shadow, and rounded corners, providing a clean and elevated look, and adapts to light and dark themes.
- Header: Displays the title “Password Generator” and a brief description about creating a secure password.
- Password Length Input: Provides an input field for the user to set the desired password length, with minimum and maximum values.
- Character Type Checkboxes: Includes checkboxes for selecting character types (uppercase, lowercase, numbers, symbols), each with a label and change handler.
- Generate Button: Triggers the
generatePassword
function to create a new password based on the selected options. - Generated Password Display: Shows the generated password in a read-only input field, along with a button to copy the password to the clipboard using the
copyToClipboard
function.
(Bonus just for you): Full Code with Comments
"use client"; // Enables client-side rendering for this component
// Import necessary hooks from React
import { useState, ChangeEvent } from "react";
// Import custom UI components from the UI directory
import {
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
} from "@/components/ui/card";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Checkbox, CheckedState } from "@/components/ui/checkbox";
import { Button } from "@/components/ui/button";
// Default export of the GeneratePasswordComponent function
export default function GeneratePasswordComponent() {
// State hooks for managing password generation options and the generated password
const [length, setLength] = useState<number>(16);
const [includeUppercase, setIncludeUppercase] = useState<boolean>(true);
const [includeLowercase, setIncludeLowercase] = useState<boolean>(true);
const [includeNumbers, setIncludeNumbers] = useState<boolean>(true);
const [includeSymbols, setIncludeSymbols] = useState<boolean>(true);
const [password, setPassword] = useState<string>("");
// Handler for updating the length state on input change
const handleLengthChange = (e: ChangeEvent<HTMLInputElement>): void => {
setLength(Number(e.target.value));
};
// Function to generate a password based on selected options
const generatePassword = (): void => {
const uppercaseChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const lowercaseChars = "abcdefghijklmnopqrstuvwxyz";
const numberChars = "0123456789";
const symbolChars = "!@#$%^&*()_+[]{}|;:,.<>?";
let allChars = "";
if (includeUppercase) allChars += uppercaseChars;
if (includeLowercase) allChars += lowercaseChars;
if (includeNumbers) allChars += numberChars;
if (includeSymbols) allChars += symbolChars;
if (allChars === "") {
alert("Please select at least one character type."); // Alert if no character types are selected
return;
}
let generatedPassword = "";
for (let i = 0; i < length; i++) {
const randomIndex = Math.floor(Math.random() * allChars.length);
generatedPassword += allChars[randomIndex]; // Generate password character by character
}
setPassword(generatedPassword); // Set the generated password state
};
// Function to copy the password to the clipboard
const copyToClipboard = (): void => {
navigator.clipboard.writeText(password).then(
() => {
alert("Password copied to clipboard!"); // Alert on successful copy
},
(err) => {
alert("Failed to copy password to clipboard."); // Alert on failed copy
}
);
};
// Handler for updating the checkbox states
const handleCheckboxChange =
(setter: (value: boolean) => void) =>
(checked: CheckedState): void => {
if (typeof checked === "boolean") {
setter(checked);
}
};
// JSX return statement rendering the password generator UI
return (
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-100 dark:bg-gray-900">
{/* Center the password generator card within the screen */}
<Card className="w-full max-w-md p-6 bg-white dark:bg-gray-800 shadow-lg rounded-lg">
<div className="mx-auto max-w-md space-y-6">
{/* Header with title and description */}
<div className="space-y-2 text-center">
<h1 className="text-3xl font-bold">Password Generator</h1>
<p className="text-gray-500 dark:text-gray-400">
Create a secure password with just a few clicks.
</p>
</div>
{/* Main content area for password options and input */}
<div className="space-y-4">
{/* Input for password length */}
<div className="space-y-2">
<Label htmlFor="length">Password Length</Label>
<Input
id="length"
type="number"
min="8"
max="32"
value={length}
onChange={handleLengthChange}
className="w-full"
/>
</div>
{/* Checkboxes for character type inclusion */}
<div className="space-y-2">
<Label>Include:</Label>
<div className="flex items-center space-x-2">
<Checkbox
id="uppercase"
checked={includeUppercase}
onCheckedChange={handleCheckboxChange(setIncludeUppercase)}
/>
<Label htmlFor="uppercase">Uppercase Letters</Label>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="lowercase"
checked={includeLowercase}
onCheckedChange={handleCheckboxChange(setIncludeLowercase)}
/>
<Label htmlFor="lowercase">Lowercase Letters</Label>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="numbers"
checked={includeNumbers}
onCheckedChange={handleCheckboxChange(setIncludeNumbers)}
/>
<Label htmlFor="numbers">Numbers</Label>
</div>
<div className="flex items-center space-x-2">
<Checkbox
id="symbols"
checked={includeSymbols}
onCheckedChange={handleCheckboxChange(setIncludeSymbols)}
/>
<Label htmlFor="symbols">Symbols</Label>
</div>
</div>
{/* Button to generate password */}
<Button type="button" className="w-full" onClick={generatePassword}>
Generate Password
</Button>
{/* Display the generated password and button to copy */}
<div className="space-y-2">
<Label htmlFor="password">Generated Password</Label>
<div className="flex items-center space-x-2">
<Input
id="password"
type="text"
value={password}
readOnly
className="flex-1"
/>
<Button type="button" onClick={copyToClipboard}>
Copy to Clipboard
</Button>
</div>
</div>
</div>
</div>
</Card>
</div>
);
}
Okay, you’ve completed the main component with functional UI. Now, you need to import this component into the app directory to use it in the app/page.tsx
file. Your final code should look like this:
import GeneratePassword from "@/components/password-generator";
export default function Home() {
return (
<div>
<GeneratePassword />
</div>
);
}
Running the Project
To see the password generator in action, follow these steps:
- Start the Development Server: Run
npm run dev
to start the development server. - Open in Browser: Open
http://localhost:3000
in your browser to view the application.
Make sure to test it properly (each and everything) so that we don’t have any errors in the production mode aka when we host on the internet.
Now, we want people to see our application on the internet. All you have to do is create a repository on GitHub and then push your code to it. After that, deploy the Password Generator application using Vercel.
Once you’re done with the deployment, please share the application link with me by commenting on this blog post, on Linkedin, and (most importantly, on X a.k.a. Twitter. Tag me there, and I’ll reply and appreciate your efforts) 👀
(Optional): One thing you can do on your own is to add new functionalities, enhance the styling, and improve the overall application. This way, you’ll learn something new by making modifications.
✨ Star Github Repository of the project 👈
Conclusion
In this blog post, we explored the creation of a password generator using Next.js. We covered:
- The purpose and main features of the application.
- A detailed breakdown of the
password-generator.tsx
component, explaining how each part of the code works together.
See you tomorrow with the latest project. Happy coding!
Stay updated with the latest in cutting-edge technology! Follow me:
- Twitter: @0xAsharib
- LinkedIn: Asharib Ali
- GitHub: AsharibAli
- Website: asharib.xyz
Thanks for reading!