BantuanUntuk desainer
Referensi template
Template adalah satu file HTML dengan placeholder Mustache. Daftar di halaman ini dibuat langsung dari kode validator, jadi selalu sama dengan yang diperiksa saat diunggah.
Starter memakai semua blok dan kedelapan partial dengan CSS dasar. Ubah sesukamu, lalu unggah.
Mulai cepat
- Mulai dari kerangka di bawah, atau dari starter template yang memakai semua blok dan kedelapan partial.
- Pakai field dari daftar Field baku; kolom Keterangan menjelaskan arti dan kapan nilainya kosong.
- Cek dengan validator sampai tidak ada yang ditolak.
- Unggah di Template saya, lalu periksa pratinjaunya dengan data contoh lengkap dan minim.
Kerangka ini adalah template terkecil yang lolos validator tanpa peringatan: layar pembuka, nama mempelai, sesi akad dan resepsi, amplop digital, dan konfirmasi kehadiran.
<!doctype html>
<html lang="id">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{couple_short}}</title>
<style>
body { margin: 0; font-family: Georgia, serif; text-align: center; }
section { padding: 3rem 1.25rem; max-width: 32rem; margin: 0 auto; }
.cover { min-height: 100svh; display: grid; place-content: center; gap: 1rem; }
html.fu-opened .cover { display: none; }
.fu-rsvp[data-state="sending"] .fu-rsvp__submit { opacity: .6; }
.fu-copy[data-state="copied"] { color: seagreen; }
</style>
</head>
<body>
<section class="cover">
<p>Kepada Yth. {{> guest_name}}</p>
<h1>{{couple_short}}</h1>
{{> open_button}}
</section>
<section>
<p>{{opening_text}}</p>
<h2>{{first.full_name}}</h2><p>{{first.parents_line}}</p>
<h2>{{second.full_name}}</h2><p>{{second.parents_line}}</p>
</section>
{{#akad}}<section>
<h2>{{title}}</h2>
<p>{{date_long}}, {{time_range}}</p>
<p>{{venue_name}}</p>
<a href="{{calendar_url}}">Simpan ke kalender</a>
</section>{{/akad}}
{{#resepsi}}<section>
<h2>{{title}}</h2>
<p>{{date_long}}, {{time_range}}</p>
<p>{{venue_name}}</p>
<a href="{{calendar_url}}">Simpan ke kalender</a>
</section>{{/resepsi}}
{{#has_gifts}}<section>
<h2>Amplop digital</h2>
{{#gifts}}<p>{{bank_name}} {{account_number}} a.n. {{account_holder}} {{> copy_button}}</p>{{/gifts}}
</section>{{/has_gifts}}
<section><h2>Konfirmasi kehadiran</h2>{{> rsvp_form}}</section>
<section><p>{{closing_text}}</p></section>
</body>
</html>
Dasar Mustache
{{bride.full_name}}mencetak teks. Semua teks di-escape otomatis.{{#akad}}...{{/akad}}hanya dirender bila sesi akad ada. Di dalamnya, field sesi bisa ditulis langsung:{{date_long}}.{{#gifts}}...{{/gifts}}mengulang isi untuk setiap item list.{{^has_gallery}}...{{/has_gallery}}dirender bila nilainya kosong atau tidak.- Section hanya boleh pada field berjenis objek, list, atau ya/tidak. Section pada field teks ditolak.
- Template wajib berisi
<htmldan</body>, berupa UTF-8, maksimal 2 MB. Inline<script>dan<style>diizinkan.
Field baku
Field di dalam list ditulis dengan nama list-nya, misalnya gifts.bank_name; di template tulis {{bank_name}} di dalam {{#gifts}}. Contoh nilai berasal dari data contoh yang dipakai pratinjau. Field yang "bisa kosong" juga harus tampil rapi saat kosong.
| Path | Jenis | Keterangan | Contoh nilai |
|---|---|---|---|
akad | objek | Sesi akad. Null bila tidak ada, jadi {{#akad}}...{{/akad}} tidak dirender. | |
akad.address | teks | Alamat lengkap. Bisa kosong. | Jl. Tamansari No. 73, Bandung |
akad.calendar_url | teks | Tautan "Simpan ke Google Calendar" yang sudah jadi. | https://calendar.google.com/calendar/render?action=TEMPLATE… |
akad.date | teks | Tanggal mentah YYYY-MM-DD. Untuk tampilan pakai date_long. | 2026-12-28 |
akad.date_iso | teks | Tanggal YYYY-MM-DD, sama dengan date. | 2026-12-28 |
akad.date_long | teks | Tanggal untuk ditampilkan, lengkap dengan nama hari dan bulan dalam bahasa Indonesia. | Senin, 28 Desember 2026 |
akad.datetime_iso | teks | Waktu mulai ISO 8601 dengan zona, untuk atribut datetime atau skrip. | 2026-12-28T08:00:00+07:00 |
akad.dress_code | teks | Aturan busana. Bisa kosong. | Batik atau kebaya |
akad.lat | teks | Garis lintang lokasi. Bisa kosong. | -6.8869 |
akad.lng | teks | Garis bujur lokasi. Bisa kosong. | 107.6105 |
akad.maps_url | teks | Tautan Google Maps lokasi. Bisa kosong. | https://maps.app.goo.gl/contoh |
akad.note | teks | Catatan tambahan sesi. Bisa kosong. | |
akad.time_end | teks | Jam selesai mentah HH:MM:SS. Kosong berarti "selesai". | 10:00:00 |
akad.time_range | teks | Jam untuk ditampilkan: "08.00 - 10.00 WIB", atau "11.00 WIB - selesai" bila tanpa jam selesai. | 08.00 - 10.00 WIB |
akad.time_start | teks | Jam mulai mentah HH:MM:SS. Untuk tampilan pakai time_range. | 08:00:00 |
akad.timezone | teks | Zona waktu: WIB, WITA, atau WIT. | WIB |
akad.title | teks | Nama sesi, misalnya "Akad Nikah". Wajib. | Akad Nikah |
akad.venue_name | teks | Nama tempat. Wajib. | Masjid Salman ITB |
bride | objek | Mempelai wanita. | |
bride.child_order | teks | Urutan anak, misalnya "Putri pertama". Bisa kosong. | Putri pertama |
bride.father_deceased | ya/tidak | true bila ayah sudah wafat. | false |
bride.father_name | teks | Nama ayah. Bisa kosong. | Ahmad Suryadi |
bride.full_name | teks | Nama lengkap. Wajib. | Rani Puspitasari |
bride.guardian | teks | Nama wali. Bisa kosong. | |
bride.instagram | teks | Username Instagram tanpa @. Bisa kosong. | rani |
bride.mother_deceased | ya/tidak | true bila ibu sudah wafat. | false |
bride.mother_name | teks | Nama ibu. Bisa kosong. | Siti Aminah |
bride.nickname | teks | Nama panggilan. Wajib. | Rani |
bride.parents_line | teks | Baris orang tua yang sudah jadi: "Bapak X & Ibu Y", dengan (Alm.)/(Almh.) bila wafat. Kosong bila nama orang tua kosong. | Bapak Ahmad Suryadi & Ibu Siti Aminah |
bride.photo_url | teks | Foto mempelai (https). Null bila tidak ada; sediakan tampilan tanpa foto. | https://freeundangan.id/static/demo/mempelai-wanita.webp |
closing_text | teks | Kalimat penutup undangan. Selalu terisi (ada teks bawaan). | Merupakan suatu kehormatan dan kebahagiaan bagi kami apabil… |
countdown_label | teks | Tanggal panjang dari sesi yang sama dengan countdown_target. | Senin, 28 Desember 2026 |
countdown_target | teks | Waktu mulai resepsi (atau akad bila tanpa resepsi), ISO 8601 dengan zona. Dipakai {{> countdown}}. | 2026-12-28T11:00:00+07:00 |
couple_order | teks | Urutan sebutan mempelai: bride_first atau groom_first. Biasanya cukup pakai first/second. | bride_first |
couple_short | teks | Nama panggilan berdua sesuai urutan, misalnya "Rani & Budi". | Rani & Budi |
cover_image_url | teks | Foto sampul (https). Bisa kosong; sediakan latar cadangan. | https://freeundangan.id/static/demo/sampul.webp |
custom | objek | Field custom yang dideklarasikan template. Isinya juga tersedia di root: {{motto}} sama dengan {{custom.motto}}. | |
extra_sessions | list | Sesi tambahan (ngunduh mantu, syukuran, dll.), urut seperti diisi pasangan. Bisa kosong. | 1 item |
extra_sessions.address | teks | Alamat lengkap. Bisa kosong. | Jl. Tamansari No. 73, Bandung |
extra_sessions.calendar_url | teks | Tautan "Simpan ke Google Calendar" yang sudah jadi. | https://calendar.google.com/calendar/render?action=TEMPLATE… |
extra_sessions.date | teks | Tanggal mentah YYYY-MM-DD. Untuk tampilan pakai date_long. | 2027-01-04 |
extra_sessions.date_iso | teks | Tanggal YYYY-MM-DD, sama dengan date. | 2027-01-04 |
extra_sessions.date_long | teks | Tanggal untuk ditampilkan, lengkap dengan nama hari dan bulan dalam bahasa Indonesia. | Senin, 4 Januari 2027 |
extra_sessions.datetime_iso | teks | Waktu mulai ISO 8601 dengan zona, untuk atribut datetime atau skrip. | 2027-01-04T10:00:00+07:00 |
extra_sessions.dress_code | teks | Aturan busana. Bisa kosong. | Batik atau kebaya |
extra_sessions.lat | teks | Garis lintang lokasi. Bisa kosong. | -6.8869 |
extra_sessions.lng | teks | Garis bujur lokasi. Bisa kosong. | 107.6105 |
extra_sessions.maps_url | teks | Tautan Google Maps lokasi. Bisa kosong. | https://maps.app.goo.gl/contoh |
extra_sessions.note | teks | Catatan tambahan sesi. Bisa kosong. | |
extra_sessions.time_end | teks | Jam selesai mentah HH:MM:SS. Kosong berarti "selesai". | 13:00:00 |
extra_sessions.time_range | teks | Jam untuk ditampilkan: "08.00 - 10.00 WIB", atau "11.00 WIB - selesai" bila tanpa jam selesai. | 10.00 - 13.00 WIB |
extra_sessions.time_start | teks | Jam mulai mentah HH:MM:SS. Untuk tampilan pakai time_range. | 10:00:00 |
extra_sessions.timezone | teks | Zona waktu: WIB, WITA, atau WIT. | WIB |
extra_sessions.title | teks | Nama sesi, misalnya "Akad Nikah". Wajib. | Ngunduh Mantu |
extra_sessions.venue_name | teks | Nama tempat. Wajib. | Kediaman Keluarga Santoso |
first | objek | Mempelai yang disebut pertama sesuai couple_order (bride atau groom). Pakai first/second agar urutan mengikuti pilihan pasangan. | |
first.child_order | teks | Urutan anak, misalnya "Putri pertama". Bisa kosong. | Putri pertama |
first.father_deceased | ya/tidak | true bila ayah sudah wafat. | false |
first.father_name | teks | Nama ayah. Bisa kosong. | Ahmad Suryadi |
first.full_name | teks | Nama lengkap. Wajib. | Rani Puspitasari |
first.guardian | teks | Nama wali. Bisa kosong. | |
first.instagram | teks | Username Instagram tanpa @. Bisa kosong. | rani |
first.mother_deceased | ya/tidak | true bila ibu sudah wafat. | false |
first.mother_name | teks | Nama ibu. Bisa kosong. | Siti Aminah |
first.nickname | teks | Nama panggilan. Wajib. | Rani |
first.parents_line | teks | Baris orang tua yang sudah jadi: "Bapak X & Ibu Y", dengan (Alm.)/(Almh.) bila wafat. Kosong bila nama orang tua kosong. | Bapak Ahmad Suryadi & Ibu Siti Aminah |
first.photo_url | teks | Foto mempelai (https). Null bila tidak ada; sediakan tampilan tanpa foto. | https://freeundangan.id/static/demo/mempelai-wanita.webp |
gallery | list | Foto galeri, urut seperti diisi pasangan. Bisa kosong; cek has_gallery. | 4 item |
gallery.url | teks | URL foto (https), lebar maksimal 1600 px. | https://freeundangan.id/static/demo/galeri-1.webp |
gift_address | teks | Alamat kirim kado fisik. Bisa kosong. | Jl. Cisitu Indah No. 12, Bandung 40135 |
gifts | list | Rekening amplop digital. Bisa kosong; cek has_gifts. | 2 item |
gifts.account_holder | teks | Nama pemilik rekening. | Rani Puspitasari |
gifts.account_number | teks | Nomor rekening, pakai dengan {{> copy_button}} agar mudah disalin. | 1234567890 |
gifts.bank_name | teks | Nama bank atau dompet digital. | BCA |
groom | objek | Mempelai pria. | |
groom.child_order | teks | Urutan anak, misalnya "Putri pertama". Bisa kosong. | Putra kedua |
groom.father_deceased | ya/tidak | true bila ayah sudah wafat. | false |
groom.father_name | teks | Nama ayah. Bisa kosong. | Hadi Santoso |
groom.full_name | teks | Nama lengkap. Wajib. | Budi Santoso |
groom.guardian | teks | Nama wali. Bisa kosong. | |
groom.instagram | teks | Username Instagram tanpa @. Bisa kosong. | budi |
groom.mother_deceased | ya/tidak | true bila ibu sudah wafat. | false |
groom.mother_name | teks | Nama ibu. Bisa kosong. | Ratna Dewi |
groom.nickname | teks | Nama panggilan. Wajib. | Budi |
groom.parents_line | teks | Baris orang tua yang sudah jadi: "Bapak X & Ibu Y", dengan (Alm.)/(Almh.) bila wafat. Kosong bila nama orang tua kosong. | Bapak Hadi Santoso & Ibu Ratna Dewi |
groom.photo_url | teks | Foto mempelai (https). Null bila tidak ada; sediakan tampilan tanpa foto. | https://freeundangan.id/static/demo/mempelai-pria.webp |
guest_fallback_text | teks | Sapaan bila tamu membuka tanpa tautan pribadi. {{> guest_name}} sudah memakainya. | Tamu Undangan |
has_akad | ya/tidak | true bila sesi akad ada. | true |
has_extra_sessions | ya/tidak | true bila ada sesi tambahan. | true |
has_gallery | ya/tidak | true bila galeri berisi foto. | true |
has_gifts | ya/tidak | true bila ada rekening amplop digital. | true |
has_love_story | ya/tidak | true bila kisah cinta diisi. | true |
has_music | ya/tidak | true bila ada musik. | true |
has_resepsi | ya/tidak | true bila sesi resepsi ada. | true |
has_video | ya/tidak | true bila video_url diisi. | true |
hashtag | teks | Hashtag pernikahan, sudah termasuk #. Bisa kosong. | #RaniBudiBerbagiCerita |
love_story | list | Kisah cinta, urut seperti diisi pasangan. Bisa kosong; cek has_love_story. | 3 item |
love_story.date | teks | Waktu momen sebagai teks bebas, misalnya "Agustus 2019" (bukan tanggal ISO). | Agustus 2019 |
love_story.text | teks | Cerita momen, bisa beberapa kalimat. | Kami bertemu di sebuah kegiatan kampus dan ternyata satu an… |
love_story.title | teks | Judul momen, misalnya "Pertama bertemu". | Pertama bertemu |
music_id | teks | ID lagu pilihan pasangan. Untuk template, pakai music_url atau {{> music_player}}. | contoh |
music_url | teks | URL berkas musik. Null bila pasangan tidak memilih musik; cek has_music. | https://files.example.com/music/contoh.mp3 |
opening_text | teks | Kalimat pembuka undangan. Selalu terisi (ada teks bawaan). | Dengan memohon rahmat Tuhan Yang Maha Esa, kami bermaksud m… |
quote | teks | Kutipan atau ayat. Bisa kosong. | Dan di antara tanda-tanda kebesaran-Nya ialah Dia menciptak… |
quote_source | teks | Sumber kutipan, misalnya "QS Ar-Rum: 21". Bisa kosong. | QS Ar-Rum: 21 |
resepsi | objek | Sesi resepsi. Null bila tidak ada, jadi {{#resepsi}}...{{/resepsi}} tidak dirender. | |
resepsi.address | teks | Alamat lengkap. Bisa kosong. | Jl. Tamansari No. 73, Bandung |
resepsi.calendar_url | teks | Tautan "Simpan ke Google Calendar" yang sudah jadi. | https://calendar.google.com/calendar/render?action=TEMPLATE… |
resepsi.date | teks | Tanggal mentah YYYY-MM-DD. Untuk tampilan pakai date_long. | 2026-12-28 |
resepsi.date_iso | teks | Tanggal YYYY-MM-DD, sama dengan date. | 2026-12-28 |
resepsi.date_long | teks | Tanggal untuk ditampilkan, lengkap dengan nama hari dan bulan dalam bahasa Indonesia. | Senin, 28 Desember 2026 |
resepsi.datetime_iso | teks | Waktu mulai ISO 8601 dengan zona, untuk atribut datetime atau skrip. | 2026-12-28T11:00:00+07:00 |
resepsi.dress_code | teks | Aturan busana. Bisa kosong. | Batik atau kebaya |
resepsi.lat | teks | Garis lintang lokasi. Bisa kosong. | -6.8869 |
resepsi.lng | teks | Garis bujur lokasi. Bisa kosong. | 107.6105 |
resepsi.maps_url | teks | Tautan Google Maps lokasi. Bisa kosong. | https://maps.app.goo.gl/contoh |
resepsi.note | teks | Catatan tambahan sesi. Bisa kosong. | |
resepsi.time_end | teks | Jam selesai mentah HH:MM:SS. Kosong berarti "selesai". | |
resepsi.time_range | teks | Jam untuk ditampilkan: "08.00 - 10.00 WIB", atau "11.00 WIB - selesai" bila tanpa jam selesai. | 11.00 WIB - selesai |
resepsi.time_start | teks | Jam mulai mentah HH:MM:SS. Untuk tampilan pakai time_range. | 11:00:00 |
resepsi.timezone | teks | Zona waktu: WIB, WITA, atau WIT. | WIB |
resepsi.title | teks | Nama sesi, misalnya "Akad Nikah". Wajib. | Resepsi |
resepsi.venue_name | teks | Nama tempat. Wajib. | Gedung Sabuga |
second | objek | Mempelai yang disebut kedua sesuai couple_order. | |
second.child_order | teks | Urutan anak, misalnya "Putri pertama". Bisa kosong. | Putra kedua |
second.father_deceased | ya/tidak | true bila ayah sudah wafat. | false |
second.father_name | teks | Nama ayah. Bisa kosong. | Hadi Santoso |
second.full_name | teks | Nama lengkap. Wajib. | Budi Santoso |
second.guardian | teks | Nama wali. Bisa kosong. | |
second.instagram | teks | Username Instagram tanpa @. Bisa kosong. | budi |
second.mother_deceased | ya/tidak | true bila ibu sudah wafat. | false |
second.mother_name | teks | Nama ibu. Bisa kosong. | Ratna Dewi |
second.nickname | teks | Nama panggilan. Wajib. | Budi |
second.parents_line | teks | Baris orang tua yang sudah jadi: "Bapak X & Ibu Y", dengan (Alm.)/(Almh.) bila wafat. Kosong bila nama orang tua kosong. | Bapak Hadi Santoso & Ibu Ratna Dewi |
second.photo_url | teks | Foto mempelai (https). Null bila tidak ada; sediakan tampilan tanpa foto. | https://freeundangan.id/static/demo/mempelai-pria.webp |
slug | teks | Alamat undangan, bagian akhir tautan (rani-budi). | contoh |
video_embed_url | teks | URL embed YouTube (https://www.youtube.com/embed/...) untuk <iframe>. Null bila video bukan YouTube. | https://www.youtube.com/embed/dQw4w9WgXcQ |
video_url | teks | Tautan video asli dari pasangan. Bisa kosong; cek has_video. | https://www.youtube.com/watch?v=dQw4w9WgXcQ |
Partial SDK
Partial menyisipkan markup interaktif yang dihidupkan SDK. Partial tidak membawa CSS; semua tampilan diatur template-mu. Partial lain selain delapan ini ditolak, dan setiap partial boleh dipakai lebih dari sekali.
{{> open_button}}
Tanpa data-state. Setelah diklik, <html> mendapat class fu-opened.
<button type="button" class="fu-open">Buka Undangan</button>
{{> guest_name}}
data-state: pending, resolved, fallback
<span class="fu-guest-name" data-state="pending" aria-busy="true">{{guest_fallback_text}}</span>
{{> rsvp_form}}
data-state: no-token, closed, idle, sending, done, error
<form class="fu-rsvp" data-state="idle" data-closes-at="{{countdown_target}}">
<p class="fu-rsvp__no-token" hidden>Konfirmasi kehadiran hanya untuk tamu undangan.</p>
<p class="fu-rsvp__closed" hidden>Konfirmasi kehadiran sudah ditutup.</p>
<fieldset class="fu-rsvp__attending">
<legend>Kehadiran</legend>
<label><input type="radio" name="attending" value="true" required> Hadir</label>
<label><input type="radio" name="attending" value="false"> Tidak hadir</label>
</fieldset>
<label class="fu-rsvp__party-size">Jumlah orang <input type="number" name="party_size" min="1" max="1" value="1" inputmode="numeric"></label>
<label class="fu-rsvp__message">Ucapan (opsional) <textarea name="message" maxlength="500"></textarea></label>
<button type="submit" class="fu-rsvp__submit">Kirim</button>
<p class="fu-rsvp__done" role="status" hidden>Terima kasih, konfirmasi tersimpan.</p>
<p class="fu-rsvp__error" role="alert" hidden>Gagal mengirim, coba lagi.</p>
</form>
{{> guestbook}}
data-state: loading, ready, empty, error
<section class="fu-guestbook" data-state="loading" aria-busy="true">
<form class="fu-guestbook__form">
<label class="fu-guestbook__name">Nama <input name="name" maxlength="60" required autocomplete="name"></label>
<label class="fu-guestbook__message">Ucapan <textarea name="message" maxlength="500" required></textarea></label>
<button type="submit" class="fu-guestbook__submit">Kirim</button>
<p class="fu-guestbook__sent" role="status" hidden>Ucapan terkirim.</p>
<p class="fu-guestbook__error" role="alert" hidden>Gagal mengirim, coba lagi.</p>
</form>
<ul class="fu-guestbook__list" aria-label="Ucapan"></ul>
<template class="fu-guestbook__item-template">
<li class="fu-guestbook__item">
<strong class="fu-guestbook__item-name"></strong>
<time class="fu-guestbook__item-time"></time>
<p class="fu-guestbook__item-message"></p>
</li>
</template>
<button type="button" class="fu-guestbook__more" hidden>Muat lagi</button>
<p class="fu-guestbook__empty" hidden>Belum ada ucapan. Jadilah yang pertama.</p>
</section>
{{> countdown}}
data-state: running, past
{{#countdown_target}}<div class="fu-countdown" data-target="{{countdown_target}}" data-state="running" role="timer" aria-label="Menuju {{countdown_label}}">
<span class="fu-countdown__unit"><span class="fu-countdown__days">0</span> <span class="fu-countdown__label">Hari</span></span>
<span class="fu-countdown__unit"><span class="fu-countdown__hours">0</span> <span class="fu-countdown__label">Jam</span></span>
<span class="fu-countdown__unit"><span class="fu-countdown__minutes">0</span> <span class="fu-countdown__label">Menit</span></span>
<span class="fu-countdown__unit"><span class="fu-countdown__seconds">0</span> <span class="fu-countdown__label">Detik</span></span>
</div>{{/countdown_target}}
{{> music_player}}
data-state: paused, playing
{{#has_music}}<button type="button" class="fu-music" data-state="paused" aria-label="Musik latar" aria-pressed="false">
<span class="fu-music__play" aria-hidden="true"></span>
<span class="fu-music__pause" aria-hidden="true"></span>
<audio class="fu-music__audio" src="{{music_url}}" loop preload="none"></audio>
</button>{{/has_music}}
{{> copy_button}}
data-state: idle, copied
<button type="button" class="fu-copy" data-copy="{{account_number}}" data-state="idle">
Salin <span class="fu-copy__done" role="status" hidden>Tersalin</span>
</button>
{{> arrival_qr}}
data-state: hidden, ready
<div class="fu-arrival" data-state="hidden" hidden>
<p class="fu-arrival__title">Kode Kedatangan</p>
<div class="fu-arrival__qr" role="img" aria-label="QR Kode Kedatangan"></div>
<p class="fu-arrival__name"></p>
<p class="fu-arrival__hint">Tunjukkan QR ini ke penerima tamu saat datang.</p>
</div>
Menata status
Status partial ada di atribut data-state pada elemen root. Pesan per status disembunyikan SDK dengan atribut hidden, sehingga template yang belum menata status tetap tampil benar. Template yang memakai partial tanpa selector .fu- atau [data-state di CSS mendapat peringatan saat diunggah.
/* Layar pembuka hilang setelah tombol buka diklik */
html.fu-opened .cover { display: none; }
/* Status di elemen root */
.fu-rsvp[data-state="sending"] .fu-rsvp__submit { opacity: .6; }
.fu-copy[data-state="copied"] { background: seagreen; color: white; }
.fu-music[data-state="playing"] .fu-music__play { display: none; }
/* Pesan yang disembunyikan SDK */
[hidden] { display: none !important; }
/* Atau beri animasi masuk dengan menimpa [hidden] */
.fu-rsvp__done { transition: opacity .3s; }
.fu-rsvp__done[hidden] { display: block; opacity: 0; }
Pratinjau template bisa memaksa status no-token, error, empty, dan closed agar setiap tampilan bisa dicek tanpa data sungguhan.
Undangan Private
Pasangan bisa menjadikan undangannya Undangan Private. Template tidak perlu diubah. Bedanya hanya pada cara halaman sampai ke tamu:
- Orang yang bukan tamu, atau membuka dari perangkat lain, melihat layar kunci platform yang berisi nama Mempelai. Isi template tidak tampil sama sekali.
- Layar kunci meminjam tampilan template: tautan Google Fonts, semua variabel di
:root, sertabackground,color, danfontdari aturanhtmldanbody. Judulnya memakai--display, atau--scriptkalau--displaytidak ada. Jadi tulis warna dan huruf utama di aturan itu, bukan hanya di elemen sampul. Deklarasi yang memakaiurl(tidak ikut dipinjam. - Di perangkat tamu, layar kunci diganti seluruhnya oleh HTML template dengan
document.write. Skrip template tetap berjalan seperti biasa, dan layar pembuka beserta tombol.fu-opentetap tampil. - SDK otomatis mengirim tanda perangkat tamu ke API, jadi partial RSVP, Buku Tamu, dan nama tamu tetap bekerja tanpa kode tambahan.
- Muat data hanya lewat field dan partial. Permintaan ke API platform yang dibuat sendiri, di luar SDK, akan ditolak pada Undangan Private.
Field custom
Butuh isian yang tidak ada di daftar field baku? Tulis nama satu kata yang belum dipakai, misalnya {{motto}} atau {{custom.motto}}. Saat diunggah, validator mencatatnya sebagai field custom dan kamu diminta mendeklarasikannya: label yang dilihat pasangan, jenis isian (text, textarea, image, atau url), dan nilai bawaan.
- Nama yang sama dengan field baku ditolak.
- Nama yang mirip field baku, misalnya
hastag, mendapat peringatan salah ketik. - Path bertitik yang tidak dikenal, misalnya
bride.nam, ditolak; bila mirip nama yang benar, pesan galatnya menyertakan saran. - Pasangan mengisi field custom di bagian Custom pada editor. Selama kosong, nilai bawaan yang dipakai.
Gambar dan aset
Atribut src, href, srcset, dan poster pada img, source, video, audio, link, script, dan iframe, juga action pada form, hanya boleh mengarah ke alamat berikut:
https://mengundang.digitalhttps://fonts.googleapis.comhttps://fonts.gstatic.comhttps://cdnjs.cloudflare.comhttps://cdn.jsdelivr.nethttps://unpkg.comhttps://www.youtube.comhttps://www.google.com/maps
- Gambar dekorasi (ornamen, tekstur, bingkai): unggah di halaman template-mu, bagian Gambar untuk template, lalu tempel URL hasilnya. JPG, PNG, atau WebP, maksimal 8 MB; gambar lebih lebar dari 1600 px diperkecil otomatis. URL-nya berada di alamat pertama di atas.
- Gambar kecil hingga 100 KB boleh ditanam sebagai URI
data:, tetapi hanya di<img>. - Foto pasangan, sampul, galeri, dan musik tidak perlu diunggah: semuanya diisi dari data undangan, misalnya
src="{{bride.photo_url}}". Nilai yang berisi placeholder dilewati saat diunggah. - Huruf dan library: Google Fonts, cdnjs, jsDelivr, atau unpkg.
- Alamat relatif seperti
ornamen.pngselalu ditolak.url()di dalam CSS tidak diperiksa validator, tetapi tetap pakai alamat di atas.
Panduan desain
- Rancang untuk HP lebih dulu. Hampir semua tamu membuka undangan dari WhatsApp di HP. Pastikan rapi di lebar 360 px, lalu lebarkan untuk layar besar.
- Viewport.
<meta name="viewport">ditambahkan otomatis bila tidak ada, tetapi tulis sendiri agar file yang dibuka langsung di browser tampil sama. - Layar pembuka. Pakai
{{> open_button}}. Setelah diklik,<html>mendapat classfu-opened; sembunyikan atau animasikan layar pembuka dengan CSS. - Data bisa kosong. Bungkus bagian opsional dengan section-nya (
{{#akad}},{{#has_gallery}}) dan sediakan tampilan tanpa foto. Cek pratinjau dengan data contoh lengkap dan minim (tambahkan?data=minimalpada alamat pratinjau). - Teks bisa panjang. Nama lengkap, alamat, dan ucapan panjangnya beragam. Hindari tinggi tetap pada kotak teks.
- Ringan. Tamu sering memakai data seluler. Pakai WebP, ukuran gambar secukupnya, dan sedikit mungkin skrip.
- Gerak secukupnya. Hormati
prefers-reduced-motionuntuk animasi. - Tanpa merek platform. Jangan menulis kredit, logo, atau tautan freeundangan di template; undangan sepenuhnya milik pasangan.
Ditolak atau peringatan
Ditolak, unggahan gagal sampai diperbaiki:
- Tidak berisi
<htmldan</body>, bukan UTF-8, atau lebih dari 2 MB. - Tag Mustache tidak seimbang, misalnya section yang tidak ditutup.
- Path bertitik yang tidak dikenal, misalnya
{{bride.nam}}. - Section pada field teks, atau list/objek yang dicetak langsung.
{{.}}di luar section list berisi teks.- Partial selain delapan partial di atas.
- Field custom yang namanya sama dengan field baku.
- Aset dengan alamat relatif, dari domain di luar daftar,
data:selain di<img>, ataudata:lebih dari 100 KB.<base href>dan<meta http-equiv="refresh">ikut diperiksa.
Peringatan, tetap bisa diunggah:
- Nama field custom yang mirip field baku, mungkin salah ketik.
- Partial dipakai, tetapi CSS tidak punya selector
.fu-atau[data-state.
Nama satu kata yang tidak dikenal tidak ditolak: nama itu dicatat sebagai field custom dan diminta dideklarasikan saat diunggah.
Cek otomatis
Validator yang sama dengan saat unggah bisa dipanggil tanpa masuk akun. Cocok untuk asisten AI yang membuatkan template: kirim isi file HTML, terima hasil dalam JSON.
curl -s -X POST -H 'Content-Type: text/html' \
--data-binary @template.html \
https://freeundangan.id/api/v1/templates/validate
{
"ok": false,
"violations": [{ "line": 12, "message": "Baris 12: field {{bride.nam}} tidak dikenal." }],
"warnings": [],
"custom_fields": [],
"partials_used": []
}
ok: falseberarti unggahan akan ditolak; perbaiki semuaviolations.warningstidak menghalangi unggahan.custom_fieldsadalah nama yang nanti diminta dideklarasikan.- Maksimal 2 MB per permintaan dan 30 permintaan per menit per alamat IP.