Setelah kita belajar event klik dan manipulasi elemen, saatnya membuat aplikasi sederhana pertama kita: Counter (penghitung angka). Counter adalah proyek fundamental untuk memahami interaktivitas JavaScript. Dengan proyek ini, kita akan mengkombinasikan event klik, manipulasi teks, dan kondisi logika.
Apa Itu Counter?
Counter adalah aplikasi sederhana yang menampilkan angka yang bisa ditambah (+), dikurangi (-), dan direset ke nilai awal. Ini adalah "Hello World" untuk interaktivitas JavaScript.
- Menyimpan nilai angka dalam variabel JavaScript
- Menampilkan nilai ke halaman dengan textContent
- Menambah dan mengurangi nilai dengan event klik
- Memberi batasan (minimal dan maksimal)
- Memberi efek visual berdasarkan nilai (warna berubah)
Counter Paling Sederhana (3 Tombol)
Mari mulai dengan counter paling dasar: tombol Tambah, Kurang, dan Reset.
Contoh Dasar:
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<title>Counter Sederhana</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #f0f4f8;
}
.counter-card {
background: white;
padding: 40px;
border-radius: 20px;
text-align: center;
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
}
.number {
font-size: 64px;
font-weight: bold;
color: #3b82f6;
margin: 20px 0;
}
button {
background: #3b82f6;
color: white;
border: none;
padding: 10px 20px;
margin: 0 5px;
border-radius: 8px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background: #2563eb;
}
.reset {
background: #ef4444;
}
.reset:hover {
background: #dc2626;
}
</style>
</head>
<body>
<div class="counter-card">
<h2>Simple Counter</h2>
<div class="number" id="counterValue">0</div>
<div>
<button id="decrementBtn">- Kurang</button>
<button id="incrementBtn">Tambah +</button>
<button id="resetBtn" class="reset">Reset</button>
</div>
</div>
<script>
let count = 0;
const counterElement = document.getElementById("counterValue");
const decrementBtn = document.getElementById("decrementBtn");
const incrementBtn = document.getElementById("incrementBtn");
const resetBtn = document.getElementById("resetBtn");
function updateDisplay() {
counterElement.textContent = count;
}
incrementBtn.addEventListener("click", function() {
count++;
updateDisplay();
});
decrementBtn.addEventListener("click", function() {
count--;
updateDisplay();
});
resetBtn.addEventListener("click", function() {
count = 0;
updateDisplay();
});
</script>
</body>
</html>
Hasilnya:
Simple Counter
Counter dengan Batasan (Min dan Max)
Kita bisa menambahkan batasan agar counter tidak bisa kurang dari nilai minimum atau lebih dari nilai maksimum.
Contoh dengan Batasan 0 - 10:
<style>
.counter-card {
background: white;
padding: 30px;
border-radius: 20px;
text-align: center;
max-width: 350px;
margin: 0 auto;
}
.number {
font-size: 60px;
font-weight: bold;
margin: 20px 0;
}
button {
background: #3b82f6;
color: white;
border: none;
padding: 10px 20px;
margin: 5px;
border-radius: 8px;
cursor: pointer;
}
button:disabled {
background: #94a3b8;
cursor: not-allowed;
}
.warning {
color: #ef4444;
font-size: 12px;
margin-top: 10px;
}
</style>
<div class="counter-card">
<h2>Counter dengan Batasan</h2>
<p>Minimal: 0 | Maksimal: 10</p>
<div class="number" id="counterWithLimit">0</div>
<div>
<button id="decrementLimit">- Kurang</button>
<button id="incrementLimit">Tambah +</button>
<button id="resetLimit" style="background: #ef4444;">Reset</button>
</div>
<div id="warningMsg" class="warning"></div>
</div>
<script>
let countLimit = 0;
const MIN = 0;
const MAX = 10;
const counterEl = document.getElementById("counterWithLimit");
const decrementBtn = document.getElementById("decrementLimit");
const incrementBtn = document.getElementById("incrementLimit");
const resetBtn = document.getElementById("resetLimit");
const warningEl = document.getElementById("warningMsg");
function updateDisplay() {
counterEl.textContent = countLimit;
decrementBtn.disabled = (countLimit <= MIN);
incrementBtn.disabled = (countLimit >= MAX);
if (countLimit <= MIN) {
warningEl.textContent = "Sudah mencapai batas minimal!";
} else if (countLimit >= MAX) {
warningEl.textContent = "Sudah mencapai batas maksimal!";
} else {
warningEl.textContent = "";
}
// Ubah warna berdasarkan nilai
if (countLimit >= 8) {
counterEl.style.color = "#ef4444";
} else if (countLimit >= 5) {
counterEl.style.color = "#f59e0b";
} else {
counterEl.style.color = "#3b82f6";
}
}
incrementBtn.addEventListener("click", function() {
if (countLimit < MAX) {
countLimit++;
updateDisplay();
}
});
decrementBtn.addEventListener("click", function() {
if (countLimit > MIN) {
countLimit--;
updateDisplay();
}
});
resetBtn.addEventListener("click", function() {
countLimit = 0;
updateDisplay();
});
updateDisplay();
</script>
Hasilnya:
Counter dengan Batasan
Minimal: 0 | Maksimal: 10
MINdanMAX→ konstanta batas nilai counterdisabled→ menonaktifkan tombol saat batas tercapai- Pesan peringatan muncul saat batas minimal/maksimal
- Warna angka berubah berdasarkan nilai (hijau muda, oranye, merah)
Counter dengan Step (Langkah)
Kita bisa mengatur berapa banyak nilai yang bertambah/berkurang setiap kali tombol diklik.
Contoh Counter dengan Step 2, 5, atau 10:
<div class="counter-card">
<h2>Counter dengan Step</h2>
<div class="number" id="counterStep">0</div>
<div>
<button id="step2">+2</button>
<button id="step5">+5</button>
<button id="step10">+10</button>
</div>
<div>
<button id="decrementStep">- Kurang</button>
<button id="resetStep" style="background: #ef4444;">Reset</button>
</div>
</div>
<script>
let countStep = 0;
const counterStepEl = document.getElementById("counterStep");
function updateStepDisplay() {
counterStepEl.textContent = countStep;
}
document.getElementById("step2").addEventListener("click", function() {
countStep += 2;
updateStepDisplay();
});
document.getElementById("step5").addEventListener("click", function() {
countStep += 5;
updateStepDisplay();
});
document.getElementById("step10").addEventListener("click", function() {
countStep += 10;
updateStepDisplay();
});
document.getElementById("decrementStep").addEventListener("click", function() {
countStep--;
updateStepDisplay();
});
document.getElementById("resetStep").addEventListener("click", function() {
countStep = 0;
updateStepDisplay();
});
</script>
Hasilnya:
Counter dengan Step
Counter dengan Animasi CSS
Kita bisa menambahkan efek animasi sederhana saat angka berubah agar lebih menarik.
Contoh Counter dengan Efek Zoom:
<style>
.number-animate {
transition: all 0.2s ease;
display: inline-block;
}
.number-animate:active {
transform: scale(1.2);
}
.btn-counter {
transition: transform 0.1s;
}
.btn-counter:active {
transform: scale(0.95);
}
</style>
<div class="counter-card">
<h2>Counter dengan Animasi</h2>
<div class="number number-animate" id="counterAnim">0</div>
<div>
<button id="decrementAnim" class="btn-counter">-</button>
<button id="incrementAnim" class="btn-counter">+</button>
<button id="resetAnim" class="btn-counter" style="background: #ef4444;">Reset</button>
</div>
</div>
<script>
let countAnim = 0;
const counterAnimEl = document.getElementById("counterAnim");
function updateAnimDisplay() {
counterAnimEl.textContent = countAnim;
// Efek animasi tambahan
counterAnimEl.style.transform = "scale(1.2)";
setTimeout(() => {
counterAnimEl.style.transform = "scale(1)";
}, 150);
}
document.getElementById("incrementAnim").addEventListener("click", function() {
countAnim++;
updateAnimDisplay();
});
document.getElementById("decrementAnim").addEventListener("click", function() {
countAnim--;
updateAnimDisplay();
});
document.getElementById("resetAnim").addEventListener("click", function() {
countAnim = 0;
updateAnimDisplay();
});
</script>
Counter dengan Animasi
Contoh Proyek: Counter untuk Jumlah Barang (Quantity Selector)
Berikut contoh counter yang sering digunakan di e-commerce untuk memilih jumlah barang:
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<title>Quantity Selector - Counter Produk</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
.product-card {
background: white;
border-radius: 24px;
padding: 30px;
max-width: 400px;
width: 100%;
text-align: center;
box-shadow: 0 20px 40px rgba(0,0,0,0.2);
}
.product-title {
font-size: 24px;
color: #1e293b;
margin-bottom: 10px;
}
.product-price {
font-size: 28px;
font-weight: bold;
color: #3b82f6;
margin-bottom: 20px;
}
.quantity-selector {
display: flex;
justify-content: center;
align-items: center;
gap: 15px;
margin-bottom: 25px;
}
.qty-btn {
background: #f0f4f8;
border: none;
width: 45px;
height: 45px;
border-radius: 12px;
font-size: 24px;
font-weight: bold;
cursor: pointer;
transition: all 0.2s;
}
.qty-btn:hover {
background: #e2e8f0;
}
.qty-btn:active {
transform: scale(0.95);
}
.qty-number {
font-size: 32px;
font-weight: bold;
width: 60px;
text-align: center;
}
.total-price {
background: #f0f4f8;
padding: 15px;
border-radius: 12px;
margin-bottom: 20px;
}
.total-price span:first-child {
color: #64748b;
}
.total-price span:last-child {
font-size: 24px;
font-weight: bold;
color: #3b82f6;
}
.add-to-cart {
background: #3b82f6;
color: white;
border: none;
width: 100%;
padding: 14px;
border-radius: 12px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
transition: background 0.2s;
}
.add-to-cart:hover {
background: #2563eb;
}
.info {
background: #eef2ff;
padding: 15px;
border-radius: 12px;
margin-top: 20px;
font-size: 13px;
}
</style>
</head>
<body>
<div class="product-card">
<h1 class="product-title">Headphone Wireless</h1>
<p class="product-price">Rp 899.000</p>
<div class="quantity-selector">
<button id="decreaseQty" class="qty-btn">-</button>
<span id="quantity" class="qty-number">1</span>
<button id="increaseQty" class="qty-btn">+</button>
</div>
<div class="total-price">
<span>Total Harga: </span>
<span id="totalPrice">Rp 899.000</span>
</div>
<button id="addToCart" class="add-to-cart">Tambah ke Keranjang</button>
<div id="message" class="info" style="display: none;"></div>
<div class="info">
Cara Kerja Counter: Tombol + dan - mengubah jumlah barang. Harga total otomatis berubah. Minimal 1, maksimal 10. Tombol "Tambah ke Keranjang" menampilkan pesan konfirmasi.
</div>
</div>
<script>
const pricePerItem = 899000;
let quantity = 1;
const MIN_QTY = 1;
const MAX_QTY = 10;
const quantityElement = document.getElementById("quantity");
const totalPriceElement = document.getElementById("totalPrice");
const decreaseBtn = document.getElementById("decreaseQty");
const increaseBtn = document.getElementById("increaseQty");
const addToCartBtn = document.getElementById("addToCart");
const messageElement = document.getElementById("message");
function formatRupiah(angka) {
return "Rp " + angka.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
}
function updateQuantityDisplay() {
quantityElement.textContent = quantity;
const total = quantity * pricePerItem;
totalPriceElement.textContent = formatRupiah(total);
decreaseBtn.disabled = (quantity <= MIN_QTY);
increaseBtn.disabled = (quantity >= MAX_QTY);
}
decreaseBtn.addEventListener("click", function() {
if (quantity > MIN_QTY) {
quantity--;
updateQuantityDisplay();
}
});
increaseBtn.addEventListener("click", function() {
if (quantity < MAX_QTY) {
quantity++;
updateQuantityDisplay();
}
});
addToCartBtn.addEventListener("click", function() {
const total = quantity * pricePerItem;
messageElement.textContent = `Berhasil menambahkan ${quantity} item ke keranjang! Total: ${formatRupiah(total)}`;
messageElement.style.display = "block";
messageElement.style.background = "#dcfce7";
messageElement.style.color = "#166534";
setTimeout(function() {
messageElement.style.display = "none";
}, 3000);
});
updateQuantityDisplay();
</script>
</body>
</html>
Hasil visual quantity selector:
Headphone Wireless
Rp 899.000
Kesalahan Umum Pemula
- Lupa mendeklarasikan variabel counter dengan let/var → Variabel harus dideklarasikan sebelum digunakan.
- Menggunakan innerHTML saat hanya butuh textContent → Untuk angka, gunakan
textContent(lebih aman dan cepat). - Tidak memberi batasan min/max → Counter bisa menjadi negatif tak terbatas atau terlalu besar.
- Tombol tidak dinonaktifkan saat batas tercapai → Pengguna bisa terus mengklik meskipun sudah batas.
- Lupa mengupdate tampilan setelah mengubah nilai → Panggil fungsi update setiap kali nilai berubah.
- Gunakan
console.log(count)untuk melihat nilai counter di console - Pastikan event listener terpasang dengan benar (coba tambahkan console.log di dalam fungsi)
- Cek apakah elemen berhasil dipilih:
console.log(counterElement)(jika null, berarti ID salah)
Latihan Singkat
- Buat file HTML baru dengan judul "Latihan Counter"
- Buat counter sederhana dengan 3 tombol: Tambah, Kurang, Reset
- Tambahkan batasan minimal 0 dan maksimal 5
- Tambahkan efek perubahan warna: hijau untuk nilai positif, merah untuk nilai negatif
- Tambahkan tombol step +5 dan -5
- Simpan dan buka di browser, coba semua tombol
Intisari Hari Ini
- Counter adalah aplikasi fundamental untuk belajar JavaScript
- Gunakan variabel untuk menyimpan nilai counter
- Gunakan textContent untuk menampilkan nilai ke halaman
- Gunakan event listener untuk merespon tombol tambah/kurang
- Tambahkan batasan (min/max) agar counter tidak keluar kendali
- Gunakan disabled untuk menonaktifkan tombol saat batas tercapai
- Counter bisa dikembangkan menjadi quantity selector, voting system, rating, dll
- Tampilkan 5 bintang (⭐) yang bisa diklik untuk memberi rating
- Saat bintang diklik, rating akan tersimpan (misal: bintang ke-3 diklik → rating 3)
- Bintang yang aktif (sesuai rating) berwarna kuning (⭐), yang tidak aktif abu-abu (☆)
- Tampilkan jumlah voting dan rata-rata rating
- Setiap kali user memberi rating, jumlah voting bertambah dan rata-rata dihitung ulang
- Tambahkan tombol "Reset Rating" untuk menghapus semua vote
- Gunakan counter untuk menyimpan total rating dan jumlah vote
- Gunakan CSS yang menarik (hover effect pada bintang)
Bonus: Simpan data rating ke localStorage agar tidak hilang saat halaman di-refresh.
Selamat mencoba!
Artikel Sebelumnya: HTML Dasar #30 - Menampilkan/Menyembunyikan Elemen dengan JavaScript
Artikel Selanjutnya: HTML Dasar #32 - Apa Itu Responsive Web Design? Pengertian Viewport
