Interactive Button Click Counter0%

Interactive Button Click Counter

Beginner12 min read•Updated: Jul 11, 2026
Study Materials

Project: Interactive Button Click Counter

Welcome to your first real-world JavaScript project! In this lesson, we will construct a clean, responsive Interactive Click Counter Application featuring state persistence, increment/decrement controls, reset capabilities, and dynamic CSS styling based on state.


1. Application Specifications

Our Click Counter must provide:

  1. 1
    Interactive UI: Increment (+), Decrement (-), and Reset buttons.
  2. 2
    Dynamic Styling: Display green text for positive numbers, red text for negative numbers, and slate text for zero.
  3. 3
    Step Selection: Allow users to increment by 1, 5, or 10.
  4. 4
    State Persistence: Save the count in the browser's localStorage so refreshing the page preserves the count!

2. The HTML Markup (index.html)

HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Counter App | MSK Institute</title>
<link rel="stylesheet" href="style.css">
<script src="counter.js" defer></script>
</head>
<body>
<div class="card">
<h2>Interactive Counter</h2>
<div id="counter-value" class="counter-display">0</div>
 
<div class="controls">
<button id="btn-decrement" class="btn btn-danger">- Decrease</button>
<button id="btn-reset" class="btn btn-secondary">Reset</button>
<button id="btn-increment" class="btn btn-success">+ Increase</button>
</div>
 
<div class="step-selector">
<label for="step">Step Value:</label>
<select id="step-select">
<option value="1" selected>1</option>
<option value="5">5</option>
<option value="10">10</option>
</select>
</div>
</div>
</body>
</html>

3. The CSS Stylesheet (style.css)

CSS
* {
box-sizing: border-box;
font-family: system-ui, -apple-system, sans-serif;
}
 
body {
background: #f1f5f9;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
 
.card {
background: #ffffff;
padding: 2.5rem;
border-radius: 1rem;
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
text-align: center;
width: 100%;
max-width: 400px;
}
 
.counter-display {
font-size: 5rem;
font-weight: 800;
margin: 1.5rem 0;
transition: color 0.2s ease, transform 0.1s ease;
}
 
.counter-positive { color: #10b981; }
.counter-negative { color: #ef4444; }
.counter-neutral { color: #64748b; }
 
.controls {
display: flex;
gap: 0.75rem;
justify-content: center;
margin-bottom: 1.5rem;
}
 
.btn {
padding: 0.75rem 1.25rem;
font-weight: 600;
border: none;
border-radius: 0.5rem;
cursor: pointer;
transition: opacity 0.2s;
}
 
.btn:hover { opacity: 0.9; }
.btn-success { background: #10b981; color: white; }
.btn-danger { background: #ef4444; color: white; }
.btn-secondary { background: #cbd5e1; color: #1e293b; }
 
.step-selector {
font-size: 0.875rem;
color: #475569;
}

4. The JavaScript Logic (counter.js)

JavaScript
// 1. Select DOM Elements
const counterDisplay = document.querySelector("#counter-value");
const btnIncrement = document.querySelector("#btn-increment");
const btnDecrement = document.querySelector("#btn-decrement");
const btnReset = document.querySelector("#btn-reset");
const stepSelect = document.querySelector("#step-select");
 
// 2. Initialize State from LocalStorage (or fallback to 0)
let count = Number(localStorage.getItem("savedCount")) || 0;
 
// 3. Render Function to update UI & Colors
function updateUI() {
counterDisplay.textContent = count;
 
// Reset classes
counterDisplay.classList.remove("counter-positive", "counter-negative", "counter-neutral");
 
// Dynamic conditional coloring:
if (count > 0) {
counterDisplay.classList.add("counter-positive");
} else if (count < 0) {
counterDisplay.classList.add("counter-negative");
} else {
counterDisplay.classList.add("counter-neutral");
}
 
// Save to localStorage
localStorage.setItem("savedCount", count);
}
 
// 4. Attach Event Listeners
btnIncrement.addEventListener("click", () => {
const step = Number(stepSelect.value);
count += step;
updateUI();
});
 
btnDecrement.addEventListener("click", () => {
const step = Number(stepSelect.value);
count -= step;
updateUI();
});
 
btnReset.addEventListener("click", () => {
count = 0;
updateUI();
});
 
// Initial render on page load
updateUI();

Interactive Quiz

Practice Quiz

Question 1
What method is used to persist data in the browser so that it survives page refreshes?
Question 2
Why is Number(localStorage.getItem("savedCount")) necessary?
Question 3
Why is creating a dedicated updateUI() function considered clean architecture?
Question 4
How do you read the currently selected numeric value of an HTML <select> element?
Question 5
What CSS transition property was added to .counter-display to ensure smooth color shifting?
Next Lesson

Simple Form Validation

Continue learning with hands-on practice, examples, and exercises in the upcoming topic.

Related Lessons

Practice Quiz

Test your understanding of this lesson with 5 questions. Each question has one correct answer.

PrevNext