Create a Voting App with HTML, CSS, and JavaScript

Faraz

By Faraz -

Learn how to create a simple voting or polling app using HTML, CSS, and JavaScript. This easy guide covers everything you need to build a fully functional voting app.


create-a-voting-polling-app-with-html-css-and-javascript.webp

Table of Contents

  1. Project Introduction
  2. HTML Code
  3. CSS Code
  4. JavaScript Code
  5. Conclusion
  6. Preview

Creating a voting or polling app using HTML, CSS, and JavaScript is a great project for beginners to practice and enhance their web development skills. In this tutorial, you'll learn how to build a simple voting app where users can cast votes and see live results. This project will help you understand core concepts like event handling, data storage, and updating the UI dynamically.

Prerequisites

Before starting this guide, you should have basic knowledge of:

  • HTML for structuring the webpage
  • CSS for styling the user interface
  • JavaScript for adding functionality and handling events
  • Chart.js for creating live result graphs

If you're comfortable with these basics, you're ready to create your voting app.

Source Code

Step 1 (HTML Code):

In index.html, write the HTML code for your app.

1. <!DOCTYPE html>:

This declaration defines the document type and version of HTML (HTML5 in this case).

2. <html lang="en">:

This is the root element of the document, setting the language of the webpage to English (en).

3. <head>:

This section contains meta information and resources for the webpage:

  • <meta charset="UTF-8">: Sets the character encoding to UTF-8 for compatibility with a wide range of characters.
  • <meta name="viewport" content="width=device-width, initial-scale=1.0">: Ensures the page is responsive by setting the viewport to match the device's width.
  • <title>Voting App</title>: Defines the title of the webpage, which appears on the browser tab.
  • <link rel="stylesheet" href="styles.css">: Links an external CSS file (styles.css) that will style the page.
  • <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>: Loads the Chart.js library from a CDN, which is used to create a dynamic chart for the voting results.

4. <body>:

The body contains the main content of the webpage. It is structured as follows:

a. <div class="app-wrapper">:

This div acts as a container for the entire voting app.

b. <header>:

Contains the app's title and description:

  • <h1>: Displays the main heading "Vote for Your Candidate".
  • <p>: A brief description encouraging users to cast their vote and see live results.

c. <main class="voting-section">:

This section allows users to vote for one of three candidates:

  • Candidate A, B, and C are presented using a candidate card, which includes:
    • An <img> element displaying the candidate's image.
    • An <h2> element for the candidate's name.
    • A <button> element that, when clicked, calls a JavaScript function vote('A'), vote('B'), or vote('C') to register the vote for that candidate.

d. <section class="results-section">:

This section shows live voting results using Chart.js and text:

  • <h2>: A heading for the section, "Live Voting Results".
  • <canvas id="resultsChart"></canvas>: A canvas element where the voting chart will be rendered by Chart.js.
  • <p>Total Votes: <span id="totalVotes">0</span></p>: Displays the total number of votes, starting at 0.
  • <div id="detailedResults" style="display:none;">: This div contains the detailed breakdown of votes for each candidate, initially hidden with display:none. It includes:
    • The number of votes each candidate has (votesA, votesB, votesC).
    • The percentage of total votes for each candidate (percentA, percentB, percentC).
  • <button id="showResults" onclick="showDetailedResults()">Show Results</button>: This button, when clicked, reveals the detailed voting breakdown by calling the showDetailedResults() function.
  • <button id="reset" onclick="resetVotes()">Reset</button>: This button, when clicked, resets the voting data by calling the resetVotes() function.

5. <script src="script.js"></script>:

The JavaScript functionality for the app is linked in this file (script.js), which contains the logic for voting, updating the chart, showing detailed results, and resetting the votes.

Step 2 (CSS Code):

In your styles.css file, write the CSS to style the app. Here's a breakdown of each section of the code:

1. Global Styles:

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Roboto', sans-serif;
}
  • The * selector applies styles to all elements:
    • margin: 0 and padding: 0 remove any default spacing around elements.
    • box-sizing: border-box makes sure that the padding and border are included in the element’s width and height.
    • font-family: 'Roboto', sans-serif applies the "Roboto" font to all text.

2. body Styling:

body {
  background-color: #825cff;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}
  • background-color: #825cff: Sets a purple background color for the whole page.
  • display: flex: The body is styled as a flexbox container to center its content.
  • justify-content: center and align-items: center: These properties center the content horizontally and vertically.
  • min-height: 100vh: Ensures the page content takes up the full height of the viewport.

3. .app-wrapper Container:

.app-wrapper {
  background-color: white;
  width: 90%;
  max-width: 1200px;
  border-radius: 12px;
  padding: 30px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
  margin: 10px;
}
  • This div is the main container for the app.
  • background-color: white: Gives the app a white background.
  • width: 90% and max-width: 1200px: Sets the width to 90% of the viewport, but limits it to a maximum of 1200px for larger screens.
  • border-radius: 12px: Rounds the corners of the container.
  • padding: 30px: Adds padding inside the container.
  • box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1): Adds a soft shadow effect around the container for a floating appearance.

4. Header Styling:

header {
  text-align: center;
  margin-bottom: 30px;
}
header h1 {
  font-size: 2.5rem;
  color: #2c3e50;
}
header p {
  color: #7f8c8d;
  font-size: 1.2rem;
  margin-top: 10px;
}
  • header: Centers the text and adds bottom margin space.
  • h1: Large font size (2.5rem) for the main heading with a dark blue color #2c3e50.
  • p: Smaller text (1.2rem) with a light grey color #7f8c8d.

5. .voting-section Styling:

.voting-section {
  display: flex;
  justify-content: space-around;
  margin-bottom: 50px;
}
  • display: flex: The candidate cards inside are arranged using flexbox.
  • justify-content: space-around: Ensures equal spacing between candidate cards.
  • margin-bottom: 50px: Adds space between the voting section and the next section.

6. .candidate-card Styling:

.candidate-card {
  background-color: #f1f2f6;
  border-radius: 10px;
  padding: 20px;
  text-align: center;
  width: 30%;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
  • Each candidate card has a light background (#f1f2f6), rounded corners, and padding inside.
  • The width is set to 30% of the container's width.
  • box-shadow: Creates a subtle shadow for depth.
  • transition: Adds smooth animation when the card is hovered, transforming its position and shadow.

7. .candidate-card img Styling:

.candidate-card img {
  width: 100%;
  border-radius: 8px;
  margin-bottom: 15px;
}
  • Ensures the candidate image takes up the full width of the card, has rounded corners, and margin below the image for spacing.

8. .candidate-card button Styling:

.candidate-card button {
  background-color: #2980b9;
  color: white;
  border: none;
  padding: 12px 25px;
  font-size: 1rem;
  border-radius: 5px;
  cursor: pointer;
  transition: background-color 0.3s ease;
}
  • The buttons have a blue background (#2980b9), white text, and rounded corners.
  • cursor: pointer: Changes the cursor to a pointer when hovering over the button.
  • transition: Smooth background color change on hover.

9. Hover Effects:

.candidate-card button:hover {
  background-color: #3498db;
}
.candidate-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
}
  • On hover, the button changes to a lighter blue (#3498db).
  • The card moves slightly upwards (translateY(-5px)) and the shadow becomes stronger.

10. .results-section Styling:

.results-section {
  text-align: center;
}
.results-section h2 {
  font-size: 2rem;
  color: #34495e;
  margin-bottom: 20px;
}
  • Centers the content and adjusts font size and color for the voting results heading.

11. .confirmation Styling:

.confirmation {
  position: fixed;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  background-color: #2ecc71;
  color: white;
  padding: 15px 20px;
  border-radius: 8px;
  font-size: 1.1rem;
  opacity: 1;
  transition: opacity 0.5s ease;
}
.confirmation.fade-out {
  opacity: 0;
}
  • This section shows a confirmation message at the bottom center of the page.
  • It is fixed in place with a green background (#2ecc71), white text, and rounded corners.
  • The fade-out class gradually reduces the opacity to 0 over 0.5 seconds, making it disappear.

12. Buttons Global Styling:

button {
  background-color: #2980b9;
  color: white;
  border: none;
  padding: 12px 25px;
  font-size: 1rem;
  border-radius: 5px;
  cursor: pointer;
  transition: background-color 0.3s ease;
  margin: 10px;
}
button:hover {
  background-color: #3498db;
}
  • Buttons share common styling across the app, with blue background, white text, padding, and hover effect.

13. canvas Styling:

canvas {
  max-width: 100%;
  height: 300px;
  margin-bottom: 20px;
}
  • The Chart.js chart is restricted to 100% width and 300px height.

14. Paragraph Styling:

p {
  font-size: 1.2rem;
  color: #2c3e50;
}
  • Paragraph text has a moderate font size and dark color (#2c3e50).

15. Media Query for Responsiveness:

@media (max-width: 768px) {
  .voting-section {
      flex-direction: column;
      align-items: center;
  }
  .candidate-card {
      width: 80%;
      margin-bottom: 20px;
  }
}
  • This media query makes the app responsive:
    • On screens smaller than 768px, the candidate cards stack vertically (flex-direction: column).
    • The width of the candidate cards is increased to 80%, and spacing between them is added.
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Roboto', sans-serif;
}

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

.app-wrapper {
  background-color: white;
  width: 90%;
  max-width: 1200px;
  border-radius: 12px;
  padding: 30px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
  margin: 10px;
}

header {
  text-align: center;
  margin-bottom: 30px;
}

header h1 {
  font-size: 2.5rem;
  color: #2c3e50;
}

header p {
  color: #7f8c8d;
  font-size: 1.2rem;
  margin-top: 10px;
}

.voting-section {
  display: flex;
  justify-content: space-around;
  margin-bottom: 50px;
}

.candidate-card {
  background-color: #f1f2f6;
  border-radius: 10px;
  padding: 20px;
  text-align: center;
  width: 30%;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.candidate-card img {
  width: 100%;
  border-radius: 8px;
  margin-bottom: 15px;
}

.candidate-card h2 {
  font-size: 1.5rem;
  color: #34495e;
  margin-bottom: 10px;
}

.candidate-card button {
  background-color: #2980b9;
  color: white;
  border: none;
  padding: 12px 25px;
  font-size: 1rem;
  border-radius: 5px;
  cursor: pointer;
  transition: background-color 0.3s ease;
}

.candidate-card button:hover {
  background-color: #3498db;
}

.candidate-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
}

.results-section {
  text-align: center;
}

.results-section h2 {
  font-size: 2rem;
  color: #34495e;
  margin-bottom: 20px;
}



.confirmation {
  position: fixed;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  background-color: #2ecc71;
  color: white;
  padding: 15px 20px;
  border-radius: 8px;
  font-size: 1.1rem;
  opacity: 1;
  transition: opacity 0.5s ease;
}

.confirmation.fade-out {
  opacity: 0;
}

button {
  background-color: #2980b9;
  color: white;
  border: none;
  padding: 12px 25px;
  font-size: 1rem;
  border-radius: 5px;
  cursor: pointer;
  transition: background-color 0.3s ease;
  margin: 10px;
}

button:hover {
  background-color: #3498db;
}

canvas {
  max-width: 100%;
  height: 300px;
  margin-bottom: 20px;
}

p {
  font-size: 1.2rem;
  color: #2c3e50;
}

@media (max-width: 768px) {
  .voting-section {
      flex-direction: column;
      align-items: center;
  }

  .candidate-card {
      width: 80%;
      margin-bottom: 20px;
  }
} 

Step 3 (JavaScript Code):

Now, in script.js, add JavaScript to manage the voting logic. Here’s how you can implement it:

Variables and Initialization:

  • votes: This object keeps track of the votes for each candidate (A, B, and C), starting from 0.
  • totalVotes: This variable tracks the total number of votes cast.

Chart Setup:

  • ctx & resultsChart: The code initializes a chart using the Chart.js library to visualize the votes in a bar chart. The chart displays three bars (one for each candidate) and is updated with real-time voting data.
    • labels: The names of the candidates are displayed on the x-axis.
    • datasets: Each dataset in Chart.js represents data for the chart. The data array contains vote counts for each candidate.
    • backgroundColor & borderColor: These arrays set the colors of the bars and their borders.
    • scales: Configures the y-axis to start at zero.

Voting Function:

  • vote(candidate): This function is called when a user votes for a candidate. It checks if the user has already voted by looking for a hasVoted key in localStorage. If they have voted, it shows an alert and prevents further voting. Otherwise:
    1. It increments the vote count for the selected candidate.
    2. It increases the totalVotes.
    3. It stores a flag (hasVoted) in localStorage to prevent the user from voting again.
    4. It calls updateResults() to refresh the chart and display the new vote totals.
    5. It calls showConfirmation() to show a message thanking the user for voting.

Results Update:

  • updateResults(): This function updates the bar chart with the latest vote data by modifying the data array and then calling update() on the chart. It also updates the displayed total number of votes.

Detailed Results:

  • showDetailedResults(): This function shows more detailed voting results by updating the HTML elements that display the vote counts for each candidate. It also calculates and shows the percentage of votes each candidate received, relative to the total votes.

Reset Votes:

  • resetVotes(): This function resets the votes for all candidates to 0, clears the hasVoted flag from localStorage, and hides the detailed results. It also updates the chart and shows an alert informing that the votes have been reset.

Show Confirmation:

  • showConfirmation(candidate): This function displays a temporary message thanking the user for voting. It creates a div element with a message and adds it to the body of the webpage. The message fades out after 3 seconds and is removed from the DOM after the fade-out transition.
let votes = {
  A: 0,
  B: 0,
  C: 0
};
let totalVotes = 0;

const ctx = document.getElementById('resultsChart').getContext('2d');
let resultsChart = new Chart(ctx, {
  type: 'bar',
  data: {
      labels: ['Candidate A', 'Candidate B', 'Candidate C'],
      datasets: [{
          label: 'Votes',
          data: [votes.A, votes.B, votes.C],
          backgroundColor: [
              '#3498db',
              '#e74c3c',
              '#2ecc71'
          ],
          borderColor: [
              '#2980b9',
              '#c0392b',
              '#27ae60'
          ],
          borderWidth: 2
      }]
  },
  options: {
      responsive: true,
      scales: {
          y: {
              beginAtZero: true
          }
      }
  }
});

function vote(candidate) {
  if (localStorage.getItem('hasVoted')) {
      alert("You've already voted!");
      return;
  }

  votes[candidate] += 1;
  totalVotes += 1;
  localStorage.setItem('hasVoted', 'true');

  updateResults();
  showConfirmation(candidate);
}

function updateResults() {
  resultsChart.data.datasets[0].data = [votes.A, votes.B, votes.C];
  resultsChart.update();

  document.getElementById('totalVotes').textContent = totalVotes;
}

function showDetailedResults() {
  document.getElementById('votesA').textContent = votes.A;
  document.getElementById('votesB').textContent = votes.B;
  document.getElementById('votesC').textContent = votes.C;

  document.getElementById('percentA').textContent = totalVotes > 0 ? ((votes.A / totalVotes) * 100).toFixed(2) + '%' : '0%';
  document.getElementById('percentB').textContent = totalVotes > 0 ? ((votes.B / totalVotes) * 100).toFixed(2) + '%' : '0%';
  document.getElementById('percentC').textContent = totalVotes > 0 ? ((votes.C / totalVotes) * 100).toFixed(2) + '%' : '0%';

  document.getElementById('detailedResults').style.display = 'block';
}

function resetVotes() {
  votes = { A: 0, B: 0, C: 0 };
  totalVotes = 0;
  localStorage.removeItem('hasVoted');

  updateResults();
  document.getElementById('detailedResults').style.display = 'none';
  alert("Votes have been reset!");
}

function showConfirmation(candidate) {
  const confirmationMessage = document.createElement('div');
  confirmationMessage.classList.add('confirmation');
  confirmationMessage.innerHTML = `Thank you for voting for Candidate ${candidate}!`;

  document.body.appendChild(confirmationMessage);
  
  setTimeout(() => {
      confirmationMessage.classList.add('fade-out');
      setTimeout(() => confirmationMessage.remove(), 500);
  }, 3000);
}

Final Output:

create-a-voting-polling-app-with-html-css-and-javascript.gif

Conclusion:

Building a voting app using HTML, CSS, and JavaScript is an exciting project that strengthens your web development skills. You now know how to set up a simple app where users can cast votes and view live results. By extending this project further, you can add features like vote validation, user authentication, or even dynamic charting for more complex applications.

This project is perfect for learning basic web development and can be modified for many other use cases, such as polls or feedback forms. Keep practicing and improving your skills by adding more features to the app!

That’s a wrap!

I hope you enjoyed this post. Now, with these examples, you can create your own amazing page.

Did you like it? Let me know in the comments below 🔥 and you can support me by buying me a coffee

And don’t forget to sign up to our email newsletter so you can get useful content like this sent right to your inbox!

Thanks!
Faraz 😊

End of the article

Subscribe to my Newsletter

Get the latest posts delivered right to your inbox


Latest Post

Please allow ads on our site🥺