
Pernahkah kalian merasa jengkel saat kode JavaScript yang sudah ditulis rapi malah bertingkah aneh? Saya pernah, lho! Dulu saat awal-awal ngoding, saya pernah coba bikin kalkulator sederhana. Setiap kali saya menekan '1' lalu '1' lagi, hasilnya malah '11', bukan '2'. Waduh, kepala langsung pusing tujuh keliling! Setelah ngoprek sana-sini, ternyata kuncinya cuma satu: lupa mengubah tipe data string menjadi angka sebelum melakukan operasi matematika. Nah, pengalaman "konyol" semacam ini justru jadi guru terbaik. Dari sana, saya belajar bahwa detail kecil bisa jadi penentu segalanya dalam membangun aplikasi web.
Kali ini, kita akan coba membuat dua aplikasi web yang cukup fundamental tapi sangat powerful untuk melatih otot frontend kita: sebuah kalkulator web dan page builder sederhana. Keduanya akan kita bangun murni menggunakan fondasi web: HTML, CSS, dan JavaScript. Tanpa framework berat, tanpa library aneh-aneh. Murni kreativitas dan logika kita!
Mengapa HTML, CSS, dan JS Murni?
Mungkin banyak dari kalian bertanya, "Kenapa tidak pakai React, Vue, atau Angular saja, Mas?" Betul, framework memang sangat membantu mempercepat pengembangan. Tapi, ibarat seorang montir mobil, sebelum kita bisa jago memodifikasi mesin V8, kita harus paham dulu bagaimana cara kerja karburator, busi, dan sistem pengapian dasar. HTML, CSS, dan JavaScript murni adalah fondasi itu. Memahami cara kerjanya tanpa abstraksi framework akan membuat kita menjadi programmer yang lebih solid dan tangguh. Ini adalah investasi jangka panjang untuk karir coding kita!
Bagian 1: Merakit Kalkulator Web Sederhana
Kalkulator adalah aplikasi yang sering diremehkan, padahal dia adalah “pusat pelatihan” yang sempurna untuk melatih logika dan penanganan event di JavaScript. Anggap saja kita sedang merakit sebuah panel kontrol untuk robot kecil. Kita butuh tombol-tombol input dan layar untuk menampilkan hasilnya.
1. Pondasi HTML (Tulang Kerangka)
Ini adalah struktur dasar kalkulator kita. Ibarat rangka robot, kita definisikan di mana layarnya dan di mana tombol-tombolnya akan berada.
<div class="calculator">
<input type="text" id="display" readonly>
<div class="buttons">
<button class="clear">C</button>
<button class="operator">/</button>
<button class="operator">*</button>
<button class="operator">-</button>
<button>7</button>
<button>8</button>
<button>9</button>
<button class="operator">+</button>
<button>4</button>
<button>5</button>
<button>6</button>
<button class="equals">=</button>
<button>1</button>
<button>2</button>
<button>3</button>
<button class="zero">0</button>
<button class="decimal">.</button>
</div>
</div>
Di sini, kita punya sebuah <input> untuk layar dan beberapa <button> untuk angka dan operator. Atribut readonly pada input penting agar user tidak bisa mengetik langsung, melainkan harus menggunakan tombol yang kita sediakan.
2. Estetika CSS (Kulit Robot)
Nah, biar robot kalkulator kita tidak cuma kotak polosan, kita perlu "memakaikannya" baju yang menarik. CSS ini seperti memilih warna cat mobil, bentuk velg, atau desain interiornya. Kita ingin kalkulator kita terlihat modern dan mudah digunakan.
.calculator {
width: 300px;
margin: 50px auto;
border: 1px solid #ccc;
border-radius: 5px;
box-shadow: 2px 2px 5px rgba(0,0,0,0.2);
padding: 15px;
background-color: #f9f9f9;
}
#display {
width: calc(100% - 20px);
height: 40px;
margin-bottom: 15px;
padding: 10px;
font-size: 1.8em;
text-align: right;
border: 1px solid #ddd;
border-radius: 3px;
box-sizing: border-box;
}
.buttons {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
}
.buttons button {
padding: 15px;
font-size: 1.2em;
border: none;
border-radius: 5px;
cursor: pointer;
background-color: #e0e0e0;
transition: background-color 0.2s;
}
.buttons button:hover {
background-color: #d0d0d0;
}
/* Styling khusus untuk operator, clear, dan equals */
.operator { background-color: #f0a04b; color: white; }
.clear { background-color: #d9534f; color: white; }
.equals { background-color: #5cb85c; color: white; grid-column: span 2; } /* Contoh: tombol = bisa lebih lebar */
Kita menggunakan CSS Grid untuk menata tombol agar rapi, dan menambahkan sedikit sentuhan warna agar terlihat lebih interaktif.
3. Otak JavaScript (Mesin Robot)
Ini adalah bagian terpenting! JavaScript-lah yang akan menghidupkan kalkulator kita. Ibarat mesin mobil, dialah yang mengatur bagaimana setiap input diproses, bagaimana angka-angka dihitung, dan bagaimana hasilnya ditampilkan di layar. Jangan sampai salah pasang kabel, nanti malah konslet!
const display = document.getElementById('display');
const buttons = document.querySelectorAll('.buttons button');
let currentInput = '';
let operator = null;
let previousInput = '';
buttons.forEach(button => {
button.addEventListener('click', (e) => {
const value = e.target.innerText;
if (value === 'C') {
currentInput = '';
operator = null;
previousInput = '';
display.value = '';
return;
}
if (value === '=') {
if (currentInput !== '' && previousInput !== '' && operator !== null) {
currentInput = String(eval(previousInput + operator + currentInput)); // Awas, eval bisa berbahaya untuk input dari user yang tidak terfilter!
previousInput = '';
operator = null;
display.value = currentInput;
}
return;
}
if (['+', '-', '*', '/'].includes(value)) {
if (currentInput === '') return; // Jangan tambahkan operator jika input kosong
if (previousInput !== '' && operator !== null) { // Jika sudah ada operasi sebelumnya, hitung dulu
currentInput = String(eval(previousInput + operator + currentInput));
previousInput = currentInput;
currentInput = '';
} else {
previousInput = currentInput;
currentInput = '';
}
operator = value;
display.value = previousInput + operator; // Tampilkan operasi di layar
return;
}
currentInput += value;
display.value = currentInput;
});
});
Di sini kita mengambil referensi ke layar dan semua tombol. Kita menambahkan event listener ke setiap tombol. Logikanya cukup sederhana: jika tombol angka, tambahkan ke currentInput. Jika operator, simpan operator dan pindahkan currentInput ke previousInput. Jika '=', hitung hasilnya. Ingat, penggunaan eval() untuk menghitung ekspresi string memang praktis, tapi sangat tidak disarankan untuk aplikasi produksi karena masalah keamanan (potensi Code Injection). Untuk proyek nyata, kalian harus membuat parser dan evaluator ekspresi sendiri, atau menggunakan library matematika yang aman.
Bagian 2: Membangun Page Builder Sederhana (Drag & Drop)
Membangun page builder itu seperti menjadi seorang arsitek sekaligus kontraktor rumah. Kalian tidak hanya mendesain tata letak, tapi juga "membangun" bagian-bagian rumahnya secara interaktif. Dulu, saya pernah coba bikin fitur drag and drop, tapi seringkali elemennya malah loncat-loncat sendiri atau malah terlempar ke luar halaman. Usut punya usut, ternyata saya lupa memanggil event.preventDefault() untuk menghentikan perilaku default browser saat ada event dragover dan drop. Nah, detail kecil seperti ini sangat krusial!
1. Fondasi HTML (Elemen-elemen Bangunan)
Kita butuh area di mana kita bisa menyeret elemen (draggable elements) dan area di mana kita bisa menjatuhkannya (drop zone).
<div class="page-builder-container">
<div class="sidebar">
<h3>Komponen</h3>
<div class="component" draggable="true" id="header">Header</div>
<div class="component" draggable="true" id="text-block">Text Block</div>
<div class="component" draggable="true" id="image-block">Image Block</div>
<div class="component" draggable="true" id="button-block">Button Block</div>
</div>
<div class="canvas" id="drop-zone">
<h3>Seret komponen ke sini!</h3>
</div>
</div>
Setiap komponen memiliki atribut draggable="true" yang penting untuk fungsionalitas drag and drop bawaan browser. #drop-zone adalah kanvas kita.
2. Estetika CSS (Dekorasi Ruangan)
CSS akan membuat page builder kita terlihat fungsional dan intuitif. Kita butuh tampilan sidebar dan area kanvas yang jelas, serta indikator visual saat elemen diseret.
.page-builder-container {
display: flex;
margin-top: 30px;
height: 70vh; /* Tinggi viewport */
border: 1px solid #eee;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
.sidebar {
width: 250px;
background-color: #f4f4f4;
padding: 20px;
border-right: 1px solid #ddd;
overflow-y: auto;
}
.component {
padding: 10px 15px;
margin-bottom: 10px;
background-color: #fff;
border: 1px solid #ccc;
border-radius: 4px;
cursor: grab;
transition: background-color 0.2s;
}
.component:hover {
background-color: #e9e9e9;
}
.canvas {
flex-grow: 1; /* Mengisi sisa ruang */
background-color: #fff;
border: 1px dashed #aaa;
margin: 20px;
padding: 20px;
text-align: center;
overflow-y: auto;
}
.canvas.hovered { /* Style saat elemen diseret di atasnya */
background-color: #e6ffe6;
border-color: #5cb85c;
}
.dropped-element {
background-color: #f0f8ff;
border: 1px solid #a0c0e0;
padding: 15px;
margin-bottom: 10px;
text-align: left;
min-height: 50px;
position: relative;
}
.dropped-element h3 { margin-top: 0; }
Kita berikan gaya pada .sidebar dan .canvas, dan juga menambahkan kelas .hovered untuk memberikan umpan balik visual saat ada elemen yang diseret di atas kanvas.
3. Otak JavaScript (Logika Tata Letak)
Bagian ini adalah "otak" di balik operasi drag and drop. Kita perlu menangani beberapa event:
dragstart: Saat elemen mulai diseret. Kita simpan data elemen yang diseret.dragover: Saat elemen diseret di atas zona drop. Ini penting untuk mencegah perilaku default browser yang melarang drop.dragleave: Saat elemen meninggalkan zona drop.drop: Saat elemen dijatuhkan di zona drop. Kita akan membuat salinan elemen dan menambahkannya ke kanvas.
const components = document.querySelectorAll('.component');
const dropZone = document.getElementById('drop-zone');
let draggedElementId = null;
components.forEach(component => {
component.addEventListener('dragstart', (e) => {
draggedElementId = e.target.id;
e.dataTransfer.setData('text/plain', e.target.id); // Simpan ID elemen yang diseret
e.target.style.opacity = '0.5'; // Beri efek visual saat diseret
});
component.addEventListener('dragend', (e) => {
e.target.style.opacity = '1'; // Kembalikan opacity
});
});
dropZone.addEventListener('dragover', (e) => {
e.preventDefault(); // Sangat penting! Mencegah default browser (misalnya membuka link)
dropZone.classList.add('hovered');
});
dropZone.addEventListener('dragleave', () => {
dropZone.classList.remove('hovered');
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault(); // Juga penting di sini!
dropZone.classList.remove('hovered');
const data = e.dataTransfer.getData('text/plain');
const originalComponent = document.getElementById(data);
if (originalComponent) {
// Buat elemen baru berdasarkan ID yang diseret
const newElement = document.createElement('div');
newElement.className = 'dropped-element'; // Beri kelas untuk styling
newElement.innerHTML = `${originalComponent.textContent}
Ini adalah ${originalComponent.textContent} baru.
`;
// Tambahkan logika untuk konten spesifik
if (data === 'header') {
newElement.innerHTML = `<h1>Judul Halaman Baru</h1>`;
} else if (data === 'text-block') {
newElement.innerHTML = `<p>Paragraf berisi teks contoh. Klik untuk mengedit.</p>`;
} else if (data === 'image-block') {
newElement.innerHTML = `<img src="https://via.placeholder.com/150" alt="Gambar Placeholder" style="max-width:100%; height:auto;">`;
} else if (data === 'button-block') {
newElement.innerHTML = `<button style="padding:10px 20px; background-color:#007bff; color:white; border:none; border-radius:5px;">Klik Saya</button>`;
}
// Contoh sederhana agar bisa diedit (opsional, butuh JS lebih lanjut)
newElement.setAttribute('contenteditable', 'true');
newElement.style.border = '1px dashed blue'; // Indikator bisa diedit
newElement.style.minHeight = '50px';
dropZone.appendChild(newElement);
// Hapus teks "Seret komponen ke sini!" jika ini elemen pertama yang dijatuhkan
const placeholderText = dropZone.querySelector('h3');
if (placeholderText && dropZone.children.length > 1) { // 1 karena newElement sudah ditambahkan
if (placeholderText.textContent === "Seret komponen ke sini!") {
placeholderText.remove();
}
}
}
});
Kode di atas adalah versi sederhana. Untuk page builder yang lebih canggih, kalian perlu menambahkan fitur seperti: mengedit teks langsung, mengubah properti CSS (ukuran font, warna, margin), menyimpan dan memuat tata letak, dan bahkan mengimplementasikan drag and drop untuk mengubah urutan elemen di dalam kanvas.
Penutup: Petualangan Masih Panjang!
Selamat! Kita sudah berhasil membangun dua aplikasi web yang cukup menarik hanya dengan mengandalkan HTML, CSS, dan JavaScript murni. Dari kalkulator yang melatih logika event dan parsing data, hingga page builder yang mengasah kemampuan kita dalam manipulasi DOM dan API Drag & Drop. Ingat, ini baru permulaan dari gunung es pengetahuan frontend.
Kini kalian bisa memodifikasi kalkulator agar punya fungsi memori atau Scientific, atau mengembangkan page builder menjadi lebih interaktif dengan menyimpan layout ke localStorage, menambahkan toolbar editing, atau bahkan mengimplementasikan fitur undo/redo. Kuncinya adalah terus bereksperimen, jangan takut error, dan selalu cari tahu "kenapa" di balik setiap baris kode. Anggap saja setiap error adalah 'tantangan' dari seorang 'pemancing ulung', yang artinya ada 'ikan besar' yang siap kita taklukkan. Selamat ngoding, para pengembang tangguh!