Developer handoff adalah saat desain berpindah dari designer ke developer, lengkap dengan semua yang dibutuhkan untuk membangunnya tanpa menebak. Bayangin denah rumah yang diserahkan ke tukang. Denah yang baik punya ukuran pasti ("pintu 80 cm"), daftar bahan ("keramik 40 × 40, abu muda"), dan catatan ("pintu kamar mandi membuka ke luar"). Tukang yang baik tetap bertanya hal yang gak ada di denah: "Stopkontak di dinding ini setinggi berapa?" Handoff adalah denah itu, ditambah daftar pertanyaan yang belum terjawab.
🧪 Tebakan cepat: Desain kartu pesan digambar dengan "Total 2 malam: Rp 700.000". Developer menulis totalnya dengan
"Rp " + (350000 * malam).toLocaleString(). Pak Hadi memakai laptop berbahasa Inggris dan memilih 3 malam. Apa yang tampil? Jawabannya ada di bagian "Edge case: data yang gak seperti di desain".
Empat isi handoff
Handoff yang lengkap punya empat bagian. Untuk kartu pesan Homestay Kabut:
| Bagian | Isinya | Di kartu pesan |
|---|---|---|
| Specs (spesifikasi) | ukuran, warna, jarak dalam nilai pasti, lewat token | tombol var(--action), tinggi 48px, padding kartu var(--space-4) |
| Assets | file yang siap dipakai | foto kamar 480, 800, dan 1200px dalam AVIF dan WebP; ikon dalam SVG |
| Interaction notes | keadaan dan perilaku | loading "Memesan...", penuh, hover, focus; total berubah saat malam diganti |
| Component docs | komponen yang dipakai dan props-nya | .btn (variant, size, state), .field, roomCard({ name, price, guests, status }) |
Di luar empat itu, handoff yang baik juga menulis edge case dan pertanyaan terbuka. Keduanya ada di bagian bawah pelajaran ini.
Spesifikasi: token, bukan angka lepas
Spesifikasi menulis nilai yang pasti, bukan "agak besar" atau "hijau yang biasa". Dan nilainya disebut lewat design token, supaya developer menulis nama yang sama:
| Bagian kartu | Spesifikasi |
|---|---|
| Kartu | padding var(--space-4) 16px, garis 1px var(--border) #e2e8f0, radius var(--radius-lg) 12px |
| Nama kamar | 1.25rem (20px), 600, var(--text) #1f2937 (14,68:1) |
| Harga | 16px, var(--text-muted) #475569 (7,58:1) |
| Pilihan malam | tinggi minimal 44px, jarak var(--space-2) 8px; yang terpilih var(--action) |
| Tombol pesan | tinggi 48px, selebar kartu, var(--action) #15803d, teks var(--on-action) (5,02:1), radius var(--radius-md) 8px |
| Catatan batal | 14px, var(--text-muted) |
Saat membangunnya, lebih baik hardcode warna atau memakai apa? Design tokens. Developer menulis background: var(--action), bukan #15803d. Kalau tema gelap datang, tombolnya ikut tanpa disentuh.
Keadaan dan perilaku
Desain yang cuma menggambar keadaan normal memaksa developer menebak sisanya. Spesifikasi tombol "hijau #15803d, tinggi 48px, teks putih" masih kurang lima keadaan: hover (var(--action-hover) #166534), active (#14532d), focus-visible (outline 3px), disabled, dan loading. Interaction notes kartu pesan:
- Memilih malam: total berubah saat itu juga, tanpa spinner (jauh di bawah 0,1 detik).
- Menekan Pesan: label jadi "Memesan...",
aria-busy="true", ketukan kedua diabaikan. Lalu dialog konfirmasi "Ya, pesan kamar" dan "Kembali". - Penuh: tombol nonaktif, abu-abu, dengan alasan "Masih kosong mulai 13 Des."
- Gagal: "Pesanan belum terkirim. Coba lagi.", pilihan malam tetap seperti tadi.
Edge case: data yang gak seperti di desain
Desain digambar dengan data yang rapi: "Kamar Teras", 2 malam, HP 375px. Data asli gak serapi itu. Kami mengukur kartunya di Chromium, WebKit, dan Firefox, dan hasilnya sama di ketiganya:
| Data | 375px | 320px |
|---|---|---|
| "Kamar Teras", 3 malam | judul 1 baris, total "Rp 1.050.000" 1 baris | sama, tapi tombol "Pesan kamar, bayar di tempat" turun jadi 2 baris: 72px |
| "Kamar Kebun Keluarga dengan Balkon Menghadap Gunung Prau" (56 huruf) | judul 2 baris, kartu 28px lebih tinggi | judul 3 baris, kartu 56px lebih tinggi |
Tombol 2 baris di 320px gak terlihat di desain 375px. Spec harus memutuskannya: dibiarkan 2 baris (masih terbaca, target sentuh justru lebih besar), atau padding halaman dikurangi di layar sempit. Begitu juga nama panjang: spec Bu Sri menulis "judul boleh turun ke baris baru, jangan dipotong dengan ...", karena nama kamar adalah yang dipesan tamu.
Lalu soal angka. toLocaleString() tanpa argumen memakai bahasa browser. Di laptop berbahasa Inggris (en-US), 1050000 ditulis "1,050,000". Jadi jawaban tebakannya: "Rp 1,050,000", dengan koma. Bagi tamu Indonesia itu janggal, karena di sini koma adalah tanda desimal. Itu jawaban tebakannya. Cara lain juga punya jebakan:
| Kode | Chromium dan Firefox | WebKit (Safari) |
|---|---|---|
n.toLocaleString() di browser en-US |
1,050,000 |
1,050,000 |
Intl.NumberFormat("id-ID", { style: "currency", currency: "IDR" }) |
Rp 1.050.000,00 |
Rp 1.050.000,00 |
sama, ditambah maximumFractionDigits: 0 |
Rp 1.050.000 |
Rp1.050.000 (tanpa spasi) |
"Rp\u00a0" + n.toLocaleString("id-ID") |
Rp 1.050.000 |
Rp 1.050.000 |
const HARGA = 350000; // Kamar Teras, per malam
function totalRupiah(malam) {
return "Rp\u00a0" + (HARGA * malam).toLocaleString("id-ID"); // "Rp 1.050.000" untuk 3 malam
}
toLocaleString("id-ID")menulis titik ribuan di browser mana pun, apa pun bahasanya.\u00a0adalah spasi tak terputus: "Rp" gak akan tertinggal sendirian di ujung baris.- Spec menulis formatnya dengan contoh: "Rp 1.050.000: Rp, satu spasi, titik ribuan, tanpa ,00". Developer gak perlu menebak.
Catatan aksesibilitas
- Pilihan malam:
role="group"denganaria-label="Lama menginap", tiap tombolaria-pressed. - Total:
aria-live="polite", jadi screen reader membacakan total baru setelah malam diganti. - Urutan fokus mengikuti urutan baca: malam, kolom isian, tombol pesan.
- Tombol penuh menulis alasannya di dekatnya, karena tombol
disabledgak bisa difokus. - Kontras sudah diukur: teks 14,68:1 dan 7,58:1, tombol 5,02:1.
Yang masih harus ditanyakan
Spec menjawab yang sudah diputuskan. Yang belum, ditulis sebagai pertanyaan terbuka, dengan nama orang yang menjawabnya:
| Pertanyaan | Yang menjawab |
|---|---|
| Berapa biaya kalau tamu batal setelah 9 Des pukul 14.00? | Bu Sri (aturan bisnis) |
| Paling banyak berapa malam bisa dipesan sekaligus? | Bu Sri |
| Bagaimana kalau dua tamu memesan malam yang sama di detik yang sama? | developer dan Bu Sri |
| Ada animasi saat kartu penuh pindah ke tanggal berikutnya? | designer |
Developer yang menemukan hal yang gak ada di spec bertanya, bukan berasumsi. Setelah dibangun, lakukan design review: buka halaman di 320, 375, 768, dan 1280px, coba tiap keadaan, dan masukkan data yang paling panjang dan paling besar.
Alatnya: Figma Dev Mode (ruang kerja Figma untuk developer: inspeksi nilai, kode yang dihasilkan, unduh assets, tanda "Ready for dev"; butuh paket berbayar dengan Full seat atau Dev seat), Storybook untuk dokumentasi komponen, atau dokumen spesifikasi biasa. Alat membantu, tapi pertanyaan terbukanya tetap harus ditulis manusia.
⚠️ Jebakan yang sering ketemu
- Spec berisi hex lepas.
#15803ddi dua puluh tempat. Tulis token:var(--action). - Cuma keadaan normal. Hover, focus-visible, disabled, loading, dan penuh gak digambar, jadi developer menebak.
- Data contoh yang terlalu rapi. "Kamar Teras" dan 2 malam gak pernah menguji judul 3 baris atau tombol 2 baris di 320px.
- Format angka diserahkan ke browser.
toLocaleString()tanpa locale memberi "1,050,000" di laptop berbahasa Inggris. - Developer berasumsi. Biaya batal yang "kira-kira" ditulis di kode jadi aturan bisnis tanpa ada yang memutuskannya.
TL;DR: Handoff berisi empat hal: specs (nilai pasti lewat token), assets (foto AVIF dan WebP, ikon SVG), interaction notes (keadaan dan perilaku), dan component docs (komponen dan props-nya); ditambah edge case dan pertanyaan terbuka. Saat membangun, pakai design tokens (var(--action)), bukan hardcode warna. Spec tombol butuh semua keadaannya: hover, active, focus-visible, disabled, loading. Uji data yang gak rapi: nama 56 huruf jadi 3 baris di 320px, dan tombol "Pesan kamar, bayar di tempat" jadi 2 baris (72px) di 320px. Tulis format angkanya: toLocaleString() di laptop en-US memberi "Rp 1,050,000"; pakai "Rp\u00a0" + n.toLocaleString("id-ID") untuk "Rp 1.050.000" di semua browser. Yang belum diputuskan masuk daftar pertanyaan terbuka dengan nama yang menjawab; developer bertanya, bukan berasumsi, lalu design review di 320, 375, 768, dan 1280px.