Survey / Poll App with HTML, CSS & JavaScript
40 DAYS 40 PROJECT CHALLENGE
Day #07
Project Overview
The Survey / Poll App is an interactive frontend project built using HTML, CSS, and JavaScript. It allows users to vote for their favorite frontend framework from four options: React, Vue, Angular, and Svelte. Users can select one option and submit their vote through the Vote button while, JavaScript validates the selection, prevents multiple votes during the same browser session using sessionStorage, and updates the voting results dynamically.
It calculates the total votes and displays each framework’s vote count and percentage. It also creates visual progress bars to represent the results clearly and the project features a clean, responsive interface with a centered poll card, styled options, and animated progress indicators. This project is useful for learning form handling, radio buttons, JavaScript objects, percentage calculations, DOM manipulation, and session storage.
Key Features
- Survey Form: The application provides a simple survey form where users can select one option from the available choices and the radio buttons ensure that users can submit only one response at a time.
- Radio Button Selection: Each framework is represented by a radio button using the same
name="option"attribute. Therefore, users can select only one option before submitting their vote. - Vote Submission: Users can submit their selected option by clicking the Vote button. The form uses JavaScript event handling to process the vote without refreshing the webpage.
- Input Validation: Before processing a vote, the application checks whether the user has selected an option. If no option is selected, an alert message asks the user to choose one.
- Single Vote Per Session: The application uses
sessionStorageto prevent users from submitting multiple votes during the same browser session. - Vote Data Management: JavaScript stores the vote count for each framework in an object. Every option starts with zero votes, and the selected framework’s count increases after a successful submission.
- Automatic Total Calculation: The application calculates the total votes using
Object.values()and thereduce()method. This total is then used to calculate the percentage for each framework. - Percentage-Based Results: Each framework displays its total number of votes and voting percentage. The percentage is calculated using the framework’s votes divided by the total votes.
- Dynamic Result Rendering: JavaScript creates result elements using
document.createElement(). It then inserts the framework name, vote count, percentage, and progress bar into the results container. - Visual Progress Bars: Each framework includes a progress bar that represents its voting percentage. The bar width changes dynamically through an inline
styleattribute. - Clean Poll Interface: The application uses a centered white card with rounded corners, spacing, and a subtle shadow. The dark blue page background creates contrast with the poll container.
What You'll Learn
- How to handle form submission with JavaScript.
- Understand how to use prevent default browser form behavior using
preventDefault(). - How to validate user input before processing a vote.
- How to store related values using JavaScript objects.
- How to calculate totals using
Object.values()andreduce(). - How to calculate percentages using mathematical expressions.
- How to use
sessionStorageto track user actions. - How to create dynamic HTML elements using the DOM.
- How to use template literals for displaying dynamic content.
- How to create percentage-based progress bars with CSS.
HTML Code
The HTML structure creates the survey interface inside the .poll-container element. It includes a heading that displays the poll question, followed by a form with four radio button options and each label contains a radio input with the same name="option" attribute, value attribute identifies the selected framework, such as React, Vue, Angular, or Svelte. This structure allows users to select one option from the available choices.
The form includes a Vote button with type="submit". JavaScript listens for the form’s submit event and processes the selected option. Below the form, the <div> element with the ID results provides an empty container where voting results are displayed dynamically.
Finally, the HTML document connects the external style.css and script.js files. The CSS file manages the visual appearance, while JavaScript handles voting logic and result generation.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Survey / Poll App</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="poll-container">
<h2>What's Your Favorite Frontend Framework?</h2>
<form id="pollForm">
<label>
<input type="radio" name="option" value="React">
React
</label>
<label>
<input type="radio" name="option" value="Vue">
Vue
</label>
<label>
<input type="radio" name="option" value="Angular">
Angular
</label>
<label>
<input type="radio" name="option" value="Svelte">
Svelte
</label>
<button type="submit">Vote</button>
</form>
<div id="results" class="results"></div>
</div>
<script src="script.js"></script>
</body>
</html> CSS Code
The CSS code creates a centered and visually clean poll interface. The body selector uses the Arial font, a dark blue background, and Flexbox properties to center the poll container horizontally and vertically and the height: 100vh property makes the layout occupy the full viewport height, .poll-container class styles the main survey card with a white background, 30px padding, a width of 400px, rounded corners, and a subtle box shadow. These properties create a compact card-style layout for the poll.
The label selector displays each voting option as a block element. The margin-bottom property adds spacing between options, while cursor: pointer makes the labels feel interactive and the button selector styles the Vote button with padding, a green background, white text, rounded corners, and a pointer cursor. The button:hover selector changes the button’s background color when the user moves the cursor over it.
The .results class adds spacing above the results section. Meanwhile, .result-item creates spacing between individual framework results, .progress class defines the outer progress bar with a light gray background, rounded edges, and hidden overflow. Finally, the .progress-bar class creates the inner progress indicator. Its initial width is 0%, and the transition: width 0.5s ease property creates a smooth animation when JavaScript updates the width.
body {
font-family: Arial, sans-serif;
background: #042354;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.poll-container {
background: white;
padding: 30px;
width: 400px;
border-radius: 10px;
box-shadow: 0 5px 20px rgba(0,0,0,0.08);
}
h2 {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 10px;
cursor: pointer;
}
button {
margin-top: 15px;
padding: 10px 20px;
border: none;
background: #4CAF50;
color: white;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background: #45a049;
}
.results {
margin-top: 20px;
}
.result-item {
margin-bottom: 10px;
}
.progress {
background: #eee;
border-radius: 20px;
height: 20px;
overflow: hidden;
margin-top: 5px;
}
.progress-bar {
height: 100%;
background: #4CAF50;
width: 0%;
transition: width 0.5s ease;
} Javascript Code
The JavaScript code manages form submission, vote validation, session-based vote restriction, percentage calculations, and dynamic result rendering. First, the code selects the poll form and results container using document.getElementById() and the votes object stores the initial vote count for each framework. When a user submits a valid vote, JavaScript increases the count for the selected framework using votes[selected.value]++. Inside the event handler, e.preventDefault() stops the browser from refreshing the page. Next, document.querySelector() searches for the selected radio button using the :checked selector.
If the user has not selected an option, the application displays an alert and stops the function. The code then checks sessionStorage.getItem("voted") to determine whether the user has already voted during the current session. If a previous vote exists, another alert message appears. After a valid vote, the selected framework’s count increases, and sessionStorage.setItem("voted", "true") records that the user has voted. The showResults() function is then called to display the updated results.
Inside showResults(), the results container is cleared using innerHTML = "". The total number of votes is calculated with Object.values(votes).reduce((a, b) => a + b, 0). The function then loops through each framework using a for...in loop. Finally, the function creates a result element, inserts the framework name, vote count, percentage, and progress bar using a template literal, and appends it to the results container.
const form = document.getElementById("pollForm");
const resultsDiv = document.getElementById("results");
// Store votes in memory
let votes = {
React: 0,
Vue: 0,
Angular: 0,
Svelte: 0
};
form.addEventListener("submit", function(e) {
e.preventDefault();
const selected = document.querySelector("input[name='option']:checked");
if (!selected) {
alert("Please select an option!");
return;
}
// Prevent multiple votes per session
if (sessionStorage.getItem("voted")) {
alert("You have already voted!");
return;
}
votes[selected.value]++;
sessionStorage.setItem("voted", "true");
showResults();
});
function showResults() {
resultsDiv.innerHTML = "";
const totalVotes = Object.values(votes).reduce((a, b) => a + b, 0);
for (let option in votes) {
const percentage = totalVotes === 0 ? 0 :
((votes[option] / totalVotes) * 100).toFixed(1);
const resultItem = document.createElement("div");
resultItem.classList.add("result-item");
resultItem.innerHTML = `
<strong>${option}</strong> - ${votes[option]} votes (${percentage}%)
<div class="progress">
<div class="progress-bar" style="width:${percentage}%"></div>
</div>
`;
resultsDiv.appendChild(resultItem);
}
} Related Projects
Day 4 : Invoice Generator
Creates invoices dynamically with item details and real-time total calculation.
Concepts: DOM manipulation, form handling, calculations, data rendering.
Day 5 : Chat UI (Frontend Only)
A simple chat interface with message sending and display functionality.
Concepts: DOM manipulation, event handling, dynamic UI updates.
Day 9 : URL Shortener (Frontend)
Shortens URLs with copy functionality and instant user feedback.
Concepts: DOM manipulation, API handling (mock), clipboard API.