JavaScript Tutorial
JavaScript Project: Counter
Plus, minus, and reset buttons that update a number on the page.
What you will build
A counter with one displayed number and three buttons: plus one, minus one, and reset to zero. Each click updates the same value in memory and writes it onto the page.
The number lives in a JavaScript variable. The heading only shows a copy of that value. If you stored the count only in the heading, a stray space or a second element would break the math.
Open an example with Try it in JavaScript. That loads /javascript/try — a live page and a console.
Methods you will use
| Method | Job on this page |
|---|---|
click | Increases, decreases, or resets the count |
state (let count) | Keeps the current number in one place |
textContent | Draws the number onto the page after every change |
addEventListener | Attaches one handler per button |
String | Turns the number into text for the heading |
One render function is enough. Plus, minus, and reset all change count, then call the same draw. Do not copy the same textContent line into three handlers.
Build in slices
Markup first. The count needs an id. Each button needs an id and type="button" so it never submits a form.
Example
<p id="count">0</p>
<button id="plus" type="button">Plus</button>
<button id="minus" type="button">Minus</button>
<button id="reset" type="button">Reset</button>Keep the number in a variable. Write a render that copies it to the page. Call that function once at start so the heading matches the variable even if you change the starting value later.
Example
let count = 0;
const display = document.getElementById("count");
function render() {
display.textContent = String(count);
}
document.getElementById("plus").addEventListener("click", function () {
count += 1;
render();
});
document.getElementById("minus").addEventListener("click", function () {
count -= 1;
render();
});
document.getElementById("reset").addEventListener("click", function () {
count = 0;
render();
});
render();Combine markup and script. Click plus twice, minus once, then reset. The heading should show 2, then 1, then 0.
Example
<p id="count">0</p>
<button id="plus" type="button">Plus</button>
<button id="minus" type="button">Minus</button>
<button id="reset" type="button">Reset</button>
<script>
let count = 0;
const display = document.getElementById("count");
function render() {
display.textContent = String(count);
}
document.getElementById("plus").addEventListener("click", function () {
count += 1;
render();
});
document.getElementById("minus").addEventListener("click", function () {
count -= 1;
render();
});
document.getElementById("reset").addEventListener("click", function () {
count = 0;
render();
});
render();
</script>Run the slice at /javascript/try with Try it in JavaScript. Watch the heading, not the console. The console can stay empty.
Complete document
This file is the counter you would keep. The number is large so clicks are obvious. Buttons sit in a row. Minus is allowed to go below zero — that is the honest default. A later practice task can clamp it.
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Counter</title>
<style>
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
background: #fefce8;
font-family: "Segoe UI", system-ui, sans-serif;
color: #1c1917;
}
.card {
width: min(20rem, 92vw);
background: #fffbeb;
border: 1px solid #fde68a;
padding: 1.4rem 1.5rem 1.55rem;
text-align: center;
}
h1 {
margin: 0 0 0.25rem;
font-size: 1.2rem;
}
#count {
margin: 0.4rem 0 1rem;
font-size: 3.2rem;
font-weight: 800;
letter-spacing: -0.04em;
}
.row {
display: flex;
gap: 0.5rem;
justify-content: center;
}
button {
min-width: 4.4rem;
padding: 0.5rem 0.7rem;
border: 0;
background: #854d0e;
color: #fffbeb;
font: inherit;
font-weight: 700;
cursor: pointer;
}
#reset {
background: #a8a29e;
color: #1c1917;
}
</style>
</head>
<body>
<article class="card">
<h1>Counter</h1>
<p id="count">0</p>
<div class="row">
<button id="minus" type="button">Minus</button>
<button id="reset" type="button">Reset</button>
<button id="plus" type="button">Plus</button>
</div>
</article>
<script>
let count = 0;
const display = document.getElementById("count");
function render() {
display.textContent = String(count);
}
document.getElementById("plus").addEventListener("click", function () {
count += 1;
render();
});
document.getElementById("minus").addEventListener("click", function () {
count -= 1;
render();
});
document.getElementById("reset").addEventListener("click", function () {
count = 0;
render();
});
render();
</script>
</body>
</html>Why the number is a variable
textContent returns a string. "10" + 1 is "101". If you read the heading and add one, you concatenate instead of counting. A let number cannot make that mistake.
render is the only place that touches the DOM. That makes later rules cheap: a minimum of zero, a step of five, a color change when the count is negative. Change the variable, then draw.
Common mistakes
- Using
const count = 0. You cannot reassign a constant. The plus button would throw. - Writing
count = count++. Postfix increment returns the old value. The count never moves. - Parsing the heading with
Number(display.textContent)as the source of truth. Keep a variable. - Attaching one listener to the card and guessing which button was clicked, before you can do that cleanly.
- Forgetting to call
renderafter reset. The variable is zero. The page still shows the old number.
Practice tasks
- Stop the count from going below zero. Minus on 0 should leave the display at 0.
- Add a Step field. Plus and minus add or subtract that number instead of 1.
- Turn the count red when it is negative and amber when it is zero. Preview at /javascript/try.