Bab-bab sebelumnya ngajarin apa yang bisa dilakuin. Bab ini soal gimana seharusnya dilakuin: prinsip dan praktik yang Shopify tetapkan biar theme cepat, bisa dirawat, dan enak dipakai merchant. Sebagian besar udah kita sentuh di tempat lain, di sini dirangkum jadi satu pegangan.

Prinsip Pemandu

Berlaku mau theme-nya buat satu merchant atau buat Theme Store:

  1. Performa: theme dibangun dengan performa sebagai prioritas, minimalkan JavaScript dan andalkan fitur browser modern dan native buat kebanyakan fungsi. Bahasannya di 57 Performance Dasar, Metrik, dan Cara Ngukur sampai 64 Performance Navigasi dan Loading.
  2. Purpose-built: layout, gaya, dan fitur theme harus berpendapat dan dioptimasi buat merchant atau segmen tertentu. Theme khusus (buat furnitur, buat fashion) lebih bernilai dari theme generik.
  3. UX terbaik di kelasnya: dengan jumlah toko Shopify yang besar, theme punya kekuatan buat membentuk pola UX ecommerce. Pelanggan didahulukan.
  4. Mobile first: mayoritas trafik dari mobile, jadi desain buat mobile sejak awal, bukan diadaptasi belakangan.
  5. Aksesibel: dibangun dari awal dengan praktik aksesibilitas, 55 Accessibility.
  6. Kustomisasi yang sederhana: merchant pakai theme buat ngekspresiin brand, jadi kasih opsi, tapi sederhana dan intuitif karena merchant mau cepat mulai jualan.

Section dan Block

Section dan block itu komponen modular yang bikin merchant bisa ngustomisasi dan memperluas theme. Panduan ini buat theme 2.0 dengan template JSON dan section group. Section statis di template Liquid atau layout gak bisa ditambah/dihapus merchant.

1. Section

Section tersedia di semua halaman. Waktu bikin template, pastiin konten default template ada di section utama (main-product, main-collection), dan section bisa ditambah, dihapus, diurutin. Pakai section buat:

  1. Nambah, ngehapus, ngurutin konten di level template atau section group.
  2. Ngontrol setting yang cakupannya seluruh layout dan konten section.

2. Block

Sediain block buat nambah/hapus/urutin konten di level section, atau kalau ningkatin kegunaan section. Tiga prinsip:

  1. Setting block cakupannya block itu (warna judul block ada di block, bukan di section).
  2. Pilih layout block yang cocok sama kontennya, dan pastiin block mengalir logis apapun tipe dan urutannya.
  3. Pilih tingkat fleksibilitas yang tepat.

Layout block: waktu desain grid section, block harus punya alur baca yang logis dan intuitif apapun tipe dan urutannya:

  1. Tumpuk vertikal buat konten teks yang butuh hierarki.
  2. Kalau gak butuh hierarki, tumpuk horizontal atau bikin grid yang beradaptasi sama tipe block yang ada.
  3. Waktu horizontal, pastiin grid bisa wrap ke beberapa baris atau sediain kontrol geser, biar lebar block tetap nyaman. Grid harus responsif. Jangan nyempitin block biar muat di viewport sempit.
  4. Jangan bergantung ke tipe atau urutan block tertentu buat nentuin layout, dan jangan pakai urutan block buat ngubah grid. Kalau kamu butuh layout tiga kolom yang pasti, kelompokkan setting-nya di satu block (block “three columns” dengan tiga set setting), bukan berharap merchant naruh tiga block image berurutan.

❌ layout bergantung urutan, rusak kalau merchant nukar

[image] [text] [image] → dua kolom gambar-teks-gambar
[text] [image] [image] → ???

✅ layout dikunci di satu block

{ "type": "columns", "settings": [ { "id": "col_1_image" }, { "id": "col_1_text" }, { "id": "col_2_image" }, ... ] }

Block dan fleksibilitas: terlalu banyak block bikin berantakan dan kompleks. Prinsipnya:

  1. Kelompokkan setting ke dalam block biar sidebar editor rapi. Setting buat ngustomisasi image block ditaruh di dalam block itu.
  2. Kalau elemen punya hierarki tertentu, kelompokkan jadi satu dan opsional sediain titik sisip sebelum dan sesudahnya. Contoh: satu block yang ngontrol semua line item cart, bukan satu block per kolom.
  3. Hindari block yang terlalu granular. Penulis, tanggal, dan jumlah komentar artikel itu satu block (atau setting), bukan tiga block terpisah. Granularitas nambah kompleksitas kode dan pengalaman editing merchant.

Ini sejalan sama batas “enam setting atau kurang” per block dari 35 Developer Preview tag {% block %} dan {% partial %}.

3. Kapan Ndukung App Block

Merchant bisa nambahin app block ke section yang ndukungnya. Pertimbangannya:

  1. Sediain di section yang punya kasus jelas buat nambah alat konversi atau faktor keputusan beli: info produk di halaman produk, template cart.
  2. Pikirin antifragility dan tujuan section: apakah layout gampang rusak kalau disisipin block tak terduga? Apakah butuh CSS kasus khusus buat nanganinnya? Apakah tujuan section jadi kabur atau gak konsisten? Kalau ya, jangan dukung app block di situ. Slideshow, misalnya, bukan tempat app block.

4. Theme Setting dan Metafield

Theme setting buat opsi tampilan, di level section, block, dan theme. Dan metafield: Shopify nyediain banyak standard metafield yang bisa cocok sama segmen target. Tinjau yang ada dan pikirin kasusnya: section atau block buat care guide atau size chart metafield, yang lewat dynamic source otomatis nampilin data produk yang lagi dirender.

Bikin block spesifik buat metafield, dan audit situs ecommerce di segmen target buat nemuin peluang komponen: daftar spesifikasi terformat buat elektronik, info blend dan asal buat kopi. Ini yang bikin theme “purpose-built”.

Tag javascript dan stylesheet

Kamu bisa ngebundel JavaScript dan CSS bareng file section, block, dan snippet pakai {% javascript %} dan {% stylesheet %} dari 12 Tags Khusus Theme. Manfaatnya: theme tetap modular, file-nya portabel antar theme dan toko tanpa kehilangan fungsi atau styling.

Kalau reusability bukan masalah, taruh JavaScript/CSS di assets dan sertakan pakai asset_url + script_tag/stylesheet_tag. Kalau aset udah disertakan di layout atau template induk, gak perlu disertakan lagi.

Peringatan utama: Liquid gak dirender di dalam dua tag ini. Nulis Liquid di situ bikin syntax error atau style gak diterapin.

1. javascript

{% javascript %}
  document.querySelector('.slideshow').slideshow();
{% endjavascript %}

Aturannya:

  1. Satu {% javascript %} per file, lebih dari satu bikin syntax error.
  2. Shopify nggabungin isi semua tag ini jadi satu file per tipe: scripts.js (section), block-scripts.js (block), snippet-scripts.js (snippet).
  3. File-nya disuntik lewat content_for_header dan dimuat asinkron dengan defer.
  4. Isi tiap tag dibungkus fungsi anonim yang langsung dieksekusi, jadi variabelnya ada di closure dan exception di satu section gak ngerusak section lain.

JavaScript per instance: aset cuma disuntik sekali per file, bukan per instance section. Kalau butuh nilai per instance (kecepatan slideshow dari setting), taruh di atribut data di markup dan baca dari JavaScript:

<div class="slideshow-wrapper" data-slide-speed="{{ section.settings.speed }}">
  <!-- slideshow content -->
</div>
{% javascript %}
  var slideshowSpeed = parseInt(document.querySelector('.slideshow-wrapper').dataset.slideSpeed);
{% endjavascript %}

Perhatiin: contoh ini cuma ngambil satu elemen. Kalau section dipakai dua kali, pakai querySelectorAll dan loop, atau custom element yang baca this.dataset.

❌ Liquid di dalam tag, gak dirender

{% javascript %}
  var speed = {{ section.settings.speed }};
{% endjavascript %}

✅ lewat atribut data

<div data-slide-speed="{{ section.settings.speed }}"></div>
{% javascript %}
  var speed = parseInt(document.querySelector('[data-slide-speed]').dataset.slideSpeed);
{% endjavascript %}

2. stylesheet

<div class="slideshow-wrapper" data-slide-speed="{{ section.settings.speed }}">
  <!-- slideshow content -->
</div>
{% stylesheet %}
.slideshow-wrapper {
  // your styles
}
{% endstylesheet %}

Satu per file. Shopify nggabungin semuanya jadi styles.css yang disuntik lewat content_for_header. Dan buat performa, Shopify nge-subset CSS-nya: tiap halaman cuma ngeload style dari file yang ada di render tree halaman itu, bukan semua CSS tiap halaman (60 Performance CSS dan Font). Style per instance (warna latar dari setting) pakai <style> inline di markup, bukan di tag ini.

Integrasi dengan Theme Editor

Dasar deteksi editor (request.design_mode, Shopify.designMode) udah di 06 Theme Editor dan Code Editor > Integrasi Theme dengan Theme Editor. Ini kelanjutannya.

Waktu merchant ngustomisasi section dan block di editor, HTML-nya ditambah, dihapus, atau dirender ulang langsung di DOM tanpa reload halaman. Tapi JavaScript yang jalan waktu page load gak jalan lagi. Jadi slider yang diinisialisasi di DOMContentLoaded bakal mati waktu section-nya ditambah merchant.

Kamu juga harus mastiin waktu section atau block dipilih, dia jadi dan tetap terlihat: slideshow scroll ke tampilan waktu section-nya dipilih, geser ke slide yang dipilih, dan pause selama dipilih.

Catatan: section dan block harus punya presets biar bisa ditambahin ke template JSON lewat editor. Tanpa presets, harus dimasukin manual ke JSON dan gak bisa dihapus lewat editor.

1. Event JavaScript

Theme editor ngenalin section dan block dari atribut data di elemen induknya. Section udah dibungkus elemen Shopify yang punya atribut itu. Block harus nambahin sendiri lewat block.shopify_attributes (dari 28 Blocks). Event-nya bubble dan gak bisa dibatalin, event.target adalah elemen section atau block-nya:

  1. shopify:inspector:activate / shopify:inspector:deactivate: preview inspector dinyalain/dimatiin.
  2. shopify:section:load ({sectionId}): section ditambah atau dirender ulang. Jalankan ulang JavaScript yang dibutuhin section, seolah halaman baru dimuat.
  3. shopify:section:unload ({sectionId}): section dihapus atau mau dirender ulang. Bersihin event listener, variabel, timer, biar gak ada yang rusak dan gak bocor memori.
  4. shopify:section:select ({sectionId, load}): section dipilih di sidebar. Editor otomatis scroll ke section, pastiin section tetap terlihat selama dipilih.
  5. shopify:section:deselect ({sectionId}).
  6. shopify:section:reorder ({sectionId}).
  7. shopify:block:select ({blockId, sectionId, load}): block dipilih. Pastiin block terlihat (geser slideshow ke slide itu).
  8. shopify:block:deselect ({blockId, sectionId}).

load bernilai true kalau event dipicu render ulang section, false kalau pilihan pengguna. Pola dasarnya:

document.addEventListener('shopify:section:load', (event) => {
  const section = event.target;
  if (section.querySelector('.slideshow')) initSlideshow(section);
});
document.addEventListener('shopify:section:unload', (event) => {
  destroySlideshow(event.target);
});
document.addEventListener('shopify:block:select', (event) => {
  const slide = event.target;
  const slideshow = slide.closest('.slideshow');
  if (slideshow) { goToSlide(slideshow, slide); pauseAutoplay(slideshow); }
});
document.addEventListener('shopify:block:deselect', (event) => {
  const slideshow = event.target.closest('.slideshow');
  if (slideshow) resumeAutoplay(slideshow);
});

Custom element (web component) ngelakuin ini otomatis: connectedCallback jalan waktu elemen masuk DOM (termasuk waktu section ditambah editor), disconnectedCallback waktu keluar. Itu alasan Dawn dan Horizon pakai custom element di mana-mana. Contoh Dawn ada di assets/theme-editor.js.

2. Deteksi Preview Inspector

Selain event-nya, variabel global Shopify.inspectMode true waktu preview inspector aktif:

if (Shopify.inspectMode) {
// This will only execute if the theme editor preview inspector is currently activated
}

3. Deteksi Visual Preview

Waktu merchant milih preset di pemilih section/block, editor nampilin visual preview (thumbnail yang dirender otomatis, dari 26 Sections dan Section Schema). Kamu bisa ngustomisasi render di mode itu, misalnya ngebuka accordion secara default biar preview-nya representatif:

{% if request.visual_preview_mode %}
  <!-- This will only render in the theme editor visual preview -->
{% endif %}
if (Shopify.visualPreviewMode) {
// This will only execute inside the theme editor's visual preview
}

Ini pengecualian dari aturan “jangan ubah tampilan di editor”: visual preview memang buat ngasih gambaran terbaik.

4. Praktik Preview Inspector

Preview inspector nggambar garis luar di sekeliling section dan block, berdasarkan Element.getBoundingClientRect(). Itu bisa nyorot fondasi theme yang biasanya gak kelihatan:

  1. Hindari margin negatif buat naruh block di section, block-nya bisa kelihatan di luar garis section.
  2. Jarak antar block pakai margin atau gap, bukan padding, karena padding bikin garis luar block gak sesuai.
  3. Nyembunyiin elemen pakai display: none atau hapus dari DOM, bukan visually hidden (posisi absolut di luar layar), karena bisa muncul garis luar tanpa elemen buat diinteraksi.
  4. Matiin elemen fixed (sticky header) waktu inspector aktif, pakai event/Shopify.inspectMode, karena bikin bingung.
  5. Kalau nduplikasi section atau block di DOM (misalnya slide yang di-clone buat loop tak terbatas), pastiin cuma satu yang punya atribut data-shopify-editor (section pakai data-shopify-editor-section, block data-shopify-editor-blocks), karena editor bergantung ke atribut itu buat ngenalin elemen.

Standard Storefront Events dan Actions

Dulu app yang mau tau kapan pembeli nambah ke cart harus baca DOM theme atau nyegat window.fetch, jadi tiap theme butuh integrasi terpisah. Standard storefront events and actions ngasih antarmuka yang sama buat semua theme dan app:

  1. Theme nge-dispatch event waktu pembeli ngelakuin sesuatu: lihat produk, update cart.
  2. App manggil action waktu butuh theme ngubah sesuatu: buka cart, update cart.

Action jalan di semua storefront Liquid tanpa setup, karena tiap action punya implementasi default. App bisa manggil updateCart di theme kamu hari ini tanpa kerjaan apa-apa dari kamu. Tapi default-nya harus jalan di theme manapun, jadi updateCart fallback ke reload halaman kalau gak ngenalin markup cart kamu. Reload ngebuang posisi scroll dan apa yang diketik pembeli.

Yang sebaiknya kamu lakuin: konfigurasi action biar ngupdate UI kamu sendiri (misalnya buka cart drawer dan render ulang lewat bundled section rendering dari 51 Ajax API dan Section Rendering API), dan dispatch event dari tempat pembeli beraksi. Daftar event, propertinya, dan parameter action ada di dokumentasi Standard storefront events dan actions. Ini standar yang relatif baru dan bakal jadi syarat integrasi app ke depan.

Transformasi File

Transformasi file bikin kamu bisa nulis kode dengan strategi dan alat build favorit, dan ngirim kode terkompilasi yang dioptimasi buat browser. Contoh: bagi stylesheet jadi banyak file kecil per komponen (gampang dirawat), terus gabungin jadi satu-dua bundle (cepat dimuat). Transformasi yang umum:

  1. Struktur file kustom → struktur theme Shopify (fleksibilitas perawatan).
  2. SCSS → CSS.
  3. SVG → snippet (inline SVG di HTML).
  4. PostCSS (Autoprefixer, cssnano, Tailwind).
  5. Folder section → file section (bikin section di file Liquid, JS, CSS, JSON terpisah).
  6. Critical CSS otomatis di-inline.
  7. Bundle JavaScript yang dioptimasi.
  8. Minifikasi JS, CSS, HTML.

Kalau kamu transformasi file, kamu harus mutusin cara ngelola source dan compiled, strateginya udah dibahas di 08 GitHub Integration dan Version Control > Version Control Strategy: Source vs Compiled.

1. Masalah Backfill

Setelah theme di-upload, merchant bisa ngubah kodenya lewat theme editor atau code editor, dan app bisa ngubah lewat Asset API. Jadi kode compiled berubah tapi source gak. Kamu harus nemuin perubahan itu dan backfill ke source, kalau gak, hilang waktu dikompilasi ulang. Ini risiko khusus buat Partner yang ngerawat theme merchant secara berkelanjutan.

Contohnya: tiga file source scopeA.js, scopeB.js, index.js di-bundle jadi index.bundle.js yang dipanggil di template:

<script src="{{ 'index.bundle.js' | asset_url }}"></script>

Merchant ngedit index.bundle.js di code editor, nambahin satu baris. Kalau theme nyambung ke GitHub, perubahan itu jadi commit dari Shopify. Waktu merchant minta fitur baru, kamu lihat commit-nya, sadar itu di file compiled, dan backport barisnya ke index.js:

import './scopeA.js'
import './scopeB.js'
+ console.log('ScopeB is way cooler than ScopeA');

Tanpa GitHub integration, kamu gak punya jejak perubahan merchant sama sekali. Itu alasan terbesar buat nyambungin theme merchant ke GitHub.

2. Just-in-time Transformation

Banyak transformasi satu arah: source → compiled, gak bisa balik. JIT transformation mindahin fungsi alat build ke layanan on-demand yang ngasilin file runtime teroptimasi dari source. Kalau kamu ngilangin kebutuhan transformasi tertentu, jumlah file compiled yang harus dibikin, dilacak, dan dirawat berkurang atau hilang. Merchant ngedit source, jadi gak perlu backfill.

Yang umum: minifikasi JavaScript, optimasi dan minifikasi CSS, manajemen dependensi pihak ketiga. Kelebihannya: kompatibel sama GitHub integration, dirawat pemilik layanannya, sesuai struktur file theme, merchant kerja di source.

Shopify udah minifikasi otomatis CSS dan JavaScript: taruh main.css di assets, Shopify ngirim versi minified yang diperbarui tiap source berubah. Jadi minifikasi bukan alasan buat punya alat build. Dan {% stylesheet %} + subsetting CSS juga ngurus “bundle dan hanya muat yang perlu” tanpa alat.

Kerja di Toko Merchant

Waktu ngembangin atau ngustomisasi theme buat merchant:

  1. Akses: pakai collaborator account (dari Partner Dashboard, cuma ke bagian toko yang diizinin merchant, gak ngitung ke batas staf) atau staff account kalau butuh yang collaborator gak bisa (admin di mobile). Minta password merchant atau pakai kredensial mereka itu dilarang. Detailnya di 04 Dev Store, Akun Kolaborator, dan Theme Access.
  2. Version control: kalau hubungannya berkelanjutan, sambungin theme ke GitHub. Tapi diskusiin dulu siapa yang ngontrol repository, merchant atau organisasi kamu. Pertimbangkan transfer repository ke merchant sebagai bagian paket akhir, biar mereka atau developer lain bisa lanjut.

Praktik yang Dilarang

Shopify ngelarang praktik pengembangan yang menipu, dan pelanggarnya kena tindakan Partner governance:

  1. Obfuscation: ngubah kode yang jelas jadi sulit dipahami, biasanya buat nyembunyiin perilaku. Juga bisa ngerusak performa. Gak ada alasan sah buat nyuntik kode obfuscated ke theme. Minifikasi bukan obfuscation (dan Shopify udah ngelakuinnya).
  2. Manipulasi mesin pencari: kode yang nampilin konten beda ke mesin pencari dan ke pengguna (cloaking), atau trik apapun buat nipu mesin pencari, termasuk buat naikin skor page speed (misalnya nyembunyiin script dari Lighthouse).

Ringkasan

  1. Prinsip: performa (minim JS), purpose-built, UX terbaik, mobile first, aksesibel, kustomisasi sederhana.
  2. Section buat konten level template/section group, konten default di section utama. Block buat level section: setting di dalam block, layout yang gak bergantung urutan/tipe block (kunci layout di satu block), granularitas sedang (kelompokkan setting, jangan tiga block buat penulis/tanggal/komentar).
  3. App block cuma di section dengan kasus jelas dan layout antifragile. Metafield standar dijadiin block spesifik sesuai segmen.
  4. {% javascript %}/{% stylesheet %}: satu per file, tanpa Liquid, digabung ke scripts.js/styles.css lewat content_for_header (defer, closure, CSS subsetting), disuntik sekali per file, nilai per instance lewat atribut data atau <style> inline.
  5. Theme editor: section ditambah tanpa reload tapi JS gak jalan lagi, dengerin shopify:section:load/unload/select/deselect/reorder dan shopify:block:select/deselect (block butuh shopify_attributes), atau pakai custom element. Deteksi request.design_mode, Shopify.designMode, Shopify.inspectMode, request.visual_preview_mode/Shopify.visualPreviewMode.
  6. Preview inspector: tanpa margin negatif, jarak pakai margin/gap, sembunyiin pakai display: none, matiin fixed, satu data-shopify-editor per elemen.
  7. Standard storefront events/actions: theme dispatch event, app panggil action, konfigurasi action biar gak fallback ke reload.
  8. Transformasi file (SCSS, PostCSS, bundling, critical CSS) butuh strategi source/compiled dan backfill perubahan merchant (ketahuan lewat commit GitHub). JIT dan minifikasi otomatis Shopify ngurangin kebutuhan alat build.
  9. Toko merchant: collaborator/staff account, jangan minta password, diskusiin kepemilikan repo.
  10. Dilarang: obfuscation dan manipulasi mesin pencari termasuk buat skor page speed.

Bab selanjutnya kita bahas aksesibilitas secara utuh: struktur semantik, navigasi keyboard dan fokus, kontras dan warna, gambar dan media, form dan error, komponen interaktif (modal, drawer, slider), dan cara ngetesnya.