Langsung ke isi
Salin

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.

Unduh starter template

Starter memakai semua blok dan kedelapan partial dengan CSS dasar. Ubah sesukamu, lalu unggah.

Mulai cepat

  1. Mulai dari kerangka di bawah, atau dari starter template yang memakai semua blok dan kedelapan partial.
  2. Pakai field dari daftar Field baku; kolom Keterangan menjelaskan arti dan kapan nilainya kosong.
  3. Cek dengan validator sampai tidak ada yang ditolak.
  4. 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 <html dan </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.

PathJenisKeteranganContoh nilai
akadobjekSesi akad. Null bila tidak ada, jadi {{#akad}}...{{/akad}} tidak dirender.
akad.addressteksAlamat lengkap. Bisa kosong.Jl. Tamansari No. 73, Bandung
akad.calendar_urlteksTautan "Simpan ke Google Calendar" yang sudah jadi.https://calendar.google.com/calendar/render?action=TEMPLATE…
akad.dateteksTanggal mentah YYYY-MM-DD. Untuk tampilan pakai date_long.2026-12-28
akad.date_isoteksTanggal YYYY-MM-DD, sama dengan date.2026-12-28
akad.date_longteksTanggal untuk ditampilkan, lengkap dengan nama hari dan bulan dalam bahasa Indonesia.Senin, 28 Desember 2026
akad.datetime_isoteksWaktu mulai ISO 8601 dengan zona, untuk atribut datetime atau skrip.2026-12-28T08:00:00+07:00
akad.dress_codeteksAturan busana. Bisa kosong.Batik atau kebaya
akad.latteksGaris lintang lokasi. Bisa kosong.-6.8869
akad.lngteksGaris bujur lokasi. Bisa kosong.107.6105
akad.maps_urlteksTautan Google Maps lokasi. Bisa kosong.https://maps.app.goo.gl/contoh
akad.noteteksCatatan tambahan sesi. Bisa kosong.
akad.time_endteksJam selesai mentah HH:MM:SS. Kosong berarti "selesai".10:00:00
akad.time_rangeteksJam untuk ditampilkan: "08.00 - 10.00 WIB", atau "11.00 WIB - selesai" bila tanpa jam selesai.08.00 - 10.00 WIB
akad.time_startteksJam mulai mentah HH:MM:SS. Untuk tampilan pakai time_range.08:00:00
akad.timezoneteksZona waktu: WIB, WITA, atau WIT.WIB
akad.titleteksNama sesi, misalnya "Akad Nikah". Wajib.Akad Nikah
akad.venue_nameteksNama tempat. Wajib.Masjid Salman ITB
brideobjekMempelai wanita.
bride.child_orderteksUrutan anak, misalnya "Putri pertama". Bisa kosong.Putri pertama
bride.father_deceasedya/tidaktrue bila ayah sudah wafat.false
bride.father_nameteksNama ayah. Bisa kosong.Ahmad Suryadi
bride.full_nameteksNama lengkap. Wajib.Rani Puspitasari
bride.guardianteksNama wali. Bisa kosong.
bride.instagramteksUsername Instagram tanpa @. Bisa kosong.rani
bride.mother_deceasedya/tidaktrue bila ibu sudah wafat.false
bride.mother_nameteksNama ibu. Bisa kosong.Siti Aminah
bride.nicknameteksNama panggilan. Wajib.Rani
bride.parents_lineteksBaris 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_urlteksFoto mempelai (https). Null bila tidak ada; sediakan tampilan tanpa foto.https://freeundangan.id/static/demo/mempelai-wanita.webp
closing_textteksKalimat penutup undangan. Selalu terisi (ada teks bawaan).Merupakan suatu kehormatan dan kebahagiaan bagi kami apabil…
countdown_labelteksTanggal panjang dari sesi yang sama dengan countdown_target.Senin, 28 Desember 2026
countdown_targetteksWaktu mulai resepsi (atau akad bila tanpa resepsi), ISO 8601 dengan zona. Dipakai {{> countdown}}.2026-12-28T11:00:00+07:00
couple_orderteksUrutan sebutan mempelai: bride_first atau groom_first. Biasanya cukup pakai first/second.bride_first
couple_shortteksNama panggilan berdua sesuai urutan, misalnya "Rani & Budi".Rani & Budi
cover_image_urlteksFoto sampul (https). Bisa kosong; sediakan latar cadangan.https://freeundangan.id/static/demo/sampul.webp
customobjekField custom yang dideklarasikan template. Isinya juga tersedia di root: {{motto}} sama dengan {{custom.motto}}.
extra_sessionslistSesi tambahan (ngunduh mantu, syukuran, dll.), urut seperti diisi pasangan. Bisa kosong.1 item
extra_sessions.addressteksAlamat lengkap. Bisa kosong.Jl. Tamansari No. 73, Bandung
extra_sessions.calendar_urlteksTautan "Simpan ke Google Calendar" yang sudah jadi.https://calendar.google.com/calendar/render?action=TEMPLATE…
extra_sessions.dateteksTanggal mentah YYYY-MM-DD. Untuk tampilan pakai date_long.2027-01-04
extra_sessions.date_isoteksTanggal YYYY-MM-DD, sama dengan date.2027-01-04
extra_sessions.date_longteksTanggal untuk ditampilkan, lengkap dengan nama hari dan bulan dalam bahasa Indonesia.Senin, 4 Januari 2027
extra_sessions.datetime_isoteksWaktu mulai ISO 8601 dengan zona, untuk atribut datetime atau skrip.2027-01-04T10:00:00+07:00
extra_sessions.dress_codeteksAturan busana. Bisa kosong.Batik atau kebaya
extra_sessions.latteksGaris lintang lokasi. Bisa kosong.-6.8869
extra_sessions.lngteksGaris bujur lokasi. Bisa kosong.107.6105
extra_sessions.maps_urlteksTautan Google Maps lokasi. Bisa kosong.https://maps.app.goo.gl/contoh
extra_sessions.noteteksCatatan tambahan sesi. Bisa kosong.
extra_sessions.time_endteksJam selesai mentah HH:MM:SS. Kosong berarti "selesai".13:00:00
extra_sessions.time_rangeteksJam untuk ditampilkan: "08.00 - 10.00 WIB", atau "11.00 WIB - selesai" bila tanpa jam selesai.10.00 - 13.00 WIB
extra_sessions.time_startteksJam mulai mentah HH:MM:SS. Untuk tampilan pakai time_range.10:00:00
extra_sessions.timezoneteksZona waktu: WIB, WITA, atau WIT.WIB
extra_sessions.titleteksNama sesi, misalnya "Akad Nikah". Wajib.Ngunduh Mantu
extra_sessions.venue_nameteksNama tempat. Wajib.Kediaman Keluarga Santoso
firstobjekMempelai yang disebut pertama sesuai couple_order (bride atau groom). Pakai first/second agar urutan mengikuti pilihan pasangan.
first.child_orderteksUrutan anak, misalnya "Putri pertama". Bisa kosong.Putri pertama
first.father_deceasedya/tidaktrue bila ayah sudah wafat.false
first.father_nameteksNama ayah. Bisa kosong.Ahmad Suryadi
first.full_nameteksNama lengkap. Wajib.Rani Puspitasari
first.guardianteksNama wali. Bisa kosong.
first.instagramteksUsername Instagram tanpa @. Bisa kosong.rani
first.mother_deceasedya/tidaktrue bila ibu sudah wafat.false
first.mother_nameteksNama ibu. Bisa kosong.Siti Aminah
first.nicknameteksNama panggilan. Wajib.Rani
first.parents_lineteksBaris 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_urlteksFoto mempelai (https). Null bila tidak ada; sediakan tampilan tanpa foto.https://freeundangan.id/static/demo/mempelai-wanita.webp
gallerylistFoto galeri, urut seperti diisi pasangan. Bisa kosong; cek has_gallery.4 item
gallery.urlteksURL foto (https), lebar maksimal 1600 px.https://freeundangan.id/static/demo/galeri-1.webp
gift_addressteksAlamat kirim kado fisik. Bisa kosong.Jl. Cisitu Indah No. 12, Bandung 40135
giftslistRekening amplop digital. Bisa kosong; cek has_gifts.2 item
gifts.account_holderteksNama pemilik rekening.Rani Puspitasari
gifts.account_numberteksNomor rekening, pakai dengan {{> copy_button}} agar mudah disalin.1234567890
gifts.bank_nameteksNama bank atau dompet digital.BCA
groomobjekMempelai pria.
groom.child_orderteksUrutan anak, misalnya "Putri pertama". Bisa kosong.Putra kedua
groom.father_deceasedya/tidaktrue bila ayah sudah wafat.false
groom.father_nameteksNama ayah. Bisa kosong.Hadi Santoso
groom.full_nameteksNama lengkap. Wajib.Budi Santoso
groom.guardianteksNama wali. Bisa kosong.
groom.instagramteksUsername Instagram tanpa @. Bisa kosong.budi
groom.mother_deceasedya/tidaktrue bila ibu sudah wafat.false
groom.mother_nameteksNama ibu. Bisa kosong.Ratna Dewi
groom.nicknameteksNama panggilan. Wajib.Budi
groom.parents_lineteksBaris 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_urlteksFoto mempelai (https). Null bila tidak ada; sediakan tampilan tanpa foto.https://freeundangan.id/static/demo/mempelai-pria.webp
guest_fallback_textteksSapaan bila tamu membuka tanpa tautan pribadi. {{> guest_name}} sudah memakainya.Tamu Undangan
has_akadya/tidaktrue bila sesi akad ada.true
has_extra_sessionsya/tidaktrue bila ada sesi tambahan.true
has_galleryya/tidaktrue bila galeri berisi foto.true
has_giftsya/tidaktrue bila ada rekening amplop digital.true
has_love_storyya/tidaktrue bila kisah cinta diisi.true
has_musicya/tidaktrue bila ada musik.true
has_resepsiya/tidaktrue bila sesi resepsi ada.true
has_videoya/tidaktrue bila video_url diisi.true
hashtagteksHashtag pernikahan, sudah termasuk #. Bisa kosong.#RaniBudiBerbagiCerita
love_storylistKisah cinta, urut seperti diisi pasangan. Bisa kosong; cek has_love_story.3 item
love_story.dateteksWaktu momen sebagai teks bebas, misalnya "Agustus 2019" (bukan tanggal ISO).Agustus 2019
love_story.textteksCerita momen, bisa beberapa kalimat.Kami bertemu di sebuah kegiatan kampus dan ternyata satu an…
love_story.titleteksJudul momen, misalnya "Pertama bertemu".Pertama bertemu
music_idteksID lagu pilihan pasangan. Untuk template, pakai music_url atau {{> music_player}}.contoh
music_urlteksURL berkas musik. Null bila pasangan tidak memilih musik; cek has_music.https://files.example.com/music/contoh.mp3
opening_textteksKalimat pembuka undangan. Selalu terisi (ada teks bawaan).Dengan memohon rahmat Tuhan Yang Maha Esa, kami bermaksud m…
quoteteksKutipan atau ayat. Bisa kosong.Dan di antara tanda-tanda kebesaran-Nya ialah Dia menciptak…
quote_sourceteksSumber kutipan, misalnya "QS Ar-Rum: 21". Bisa kosong.QS Ar-Rum: 21
resepsiobjekSesi resepsi. Null bila tidak ada, jadi {{#resepsi}}...{{/resepsi}} tidak dirender.
resepsi.addressteksAlamat lengkap. Bisa kosong.Jl. Tamansari No. 73, Bandung
resepsi.calendar_urlteksTautan "Simpan ke Google Calendar" yang sudah jadi.https://calendar.google.com/calendar/render?action=TEMPLATE…
resepsi.dateteksTanggal mentah YYYY-MM-DD. Untuk tampilan pakai date_long.2026-12-28
resepsi.date_isoteksTanggal YYYY-MM-DD, sama dengan date.2026-12-28
resepsi.date_longteksTanggal untuk ditampilkan, lengkap dengan nama hari dan bulan dalam bahasa Indonesia.Senin, 28 Desember 2026
resepsi.datetime_isoteksWaktu mulai ISO 8601 dengan zona, untuk atribut datetime atau skrip.2026-12-28T11:00:00+07:00
resepsi.dress_codeteksAturan busana. Bisa kosong.Batik atau kebaya
resepsi.latteksGaris lintang lokasi. Bisa kosong.-6.8869
resepsi.lngteksGaris bujur lokasi. Bisa kosong.107.6105
resepsi.maps_urlteksTautan Google Maps lokasi. Bisa kosong.https://maps.app.goo.gl/contoh
resepsi.noteteksCatatan tambahan sesi. Bisa kosong.
resepsi.time_endteksJam selesai mentah HH:MM:SS. Kosong berarti "selesai".
resepsi.time_rangeteksJam untuk ditampilkan: "08.00 - 10.00 WIB", atau "11.00 WIB - selesai" bila tanpa jam selesai.11.00 WIB - selesai
resepsi.time_startteksJam mulai mentah HH:MM:SS. Untuk tampilan pakai time_range.11:00:00
resepsi.timezoneteksZona waktu: WIB, WITA, atau WIT.WIB
resepsi.titleteksNama sesi, misalnya "Akad Nikah". Wajib.Resepsi
resepsi.venue_nameteksNama tempat. Wajib.Gedung Sabuga
secondobjekMempelai yang disebut kedua sesuai couple_order.
second.child_orderteksUrutan anak, misalnya "Putri pertama". Bisa kosong.Putra kedua
second.father_deceasedya/tidaktrue bila ayah sudah wafat.false
second.father_nameteksNama ayah. Bisa kosong.Hadi Santoso
second.full_nameteksNama lengkap. Wajib.Budi Santoso
second.guardianteksNama wali. Bisa kosong.
second.instagramteksUsername Instagram tanpa @. Bisa kosong.budi
second.mother_deceasedya/tidaktrue bila ibu sudah wafat.false
second.mother_nameteksNama ibu. Bisa kosong.Ratna Dewi
second.nicknameteksNama panggilan. Wajib.Budi
second.parents_lineteksBaris 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_urlteksFoto mempelai (https). Null bila tidak ada; sediakan tampilan tanpa foto.https://freeundangan.id/static/demo/mempelai-pria.webp
slugteksAlamat undangan, bagian akhir tautan (rani-budi).contoh
video_embed_urlteksURL embed YouTube (https://www.youtube.com/embed/...) untuk <iframe>. Null bila video bukan YouTube.https://www.youtube.com/embed/dQw4w9WgXcQ
video_urlteksTautan 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, serta background, color, dan font dari aturan html dan body. Judulnya memakai --display, atau --script kalau --display tidak ada. Jadi tulis warna dan huruf utama di aturan itu, bukan hanya di elemen sampul. Deklarasi yang memakai url( 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-open tetap 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.digital
  • https://fonts.googleapis.com
  • https://fonts.gstatic.com
  • https://cdnjs.cloudflare.com
  • https://cdn.jsdelivr.net
  • https://unpkg.com
  • https://www.youtube.com
  • https://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.png selalu 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 class fu-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=minimal pada 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-motion untuk 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 <html dan </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>, atau data: 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: false berarti unggahan akan ditolak; perbaiki semua violations.
  • warnings tidak menghalangi unggahan.
  • custom_fields adalah nama yang nanti diminta dideklarasikan.
  • Maksimal 2 MB per permintaan dan 30 permintaan per menit per alamat IP.