Styling Solid — SolidJS

Solid mendukung beberapa cara styling komponen. CSS Modules import styles from "./App.module.css" function App() { return Konten } classList Teks style prop…

Di Solid, tampilan elemen diatur lewat tiga prop: class untuk kelas CSS yang tetap, classList untuk kelas yang nyala-mati mengikuti kondisi, dan style untuk nilai CSS yang dihitung. Bayangin kartu buku di rak Toko Buku Kak Nadia. Semua kartu memakai bingkai yang sama, itu kelas tetapnya. Begitu sebuah buku habis, Kak Nadia menjepitkan stiker abu-abu habis di kartunya, dan mencabutnya lagi saat stok datang. Kartunya gak dicat ulang. Dia cuma menjepit atau mencabut satu stiker. classList adalah kumpulan saklar stiker itu: satu saklar per nama kelas, masing-masing mengikuti satu kondisi.

🧪 Tebakan cepat: kartu Cantik Itu Luka (stok 0) ditulis dengan class={"kartu " + tema()} dan classList={{ habis: stok() === 0 }}, jadi tampil abu-abu. Lalu tema diganti dari terang ke gelap. Kartunya masih abu-abu atau gak? Jawabannya ada di bagian "class dan classList di elemen yang sama".

class: kelas yang tetap

<div class="kartu">...</div>

Sama seperti di HTML, dan Solid menulisnya langsung ke template. Nilainya juga boleh dihitung: class={stok() === 0 ? "kartu habis" : "kartu"}. Tiap kali hasilnya berubah, Solid mengganti seluruh atribut: el.className = "kartu habis". Untuk satu kondisi ini masih rapi. Dengan dua, tiga kondisi, string-nya jadi susah dibaca.

classList: kelas yang nyala-mati

Kartu buku Toko Buku Kak Nadia, dengan stoknya sendiri:

import { createSignal } from "solid-js"

function KartuBuku(props) {
  const [stok, setStok] = createSignal(props.stokAwal)

  return (
    <div class="kartu" classList={{ habis: stok() === 0, "sisa-sedikit": stok() > 0 && stok() < 3 }}>
      <h3>{props.judul}</h3>
      <p class="harga" style={{ "text-decoration": stok() === 0 ? "line-through" : "none" }}>Rp{props.harga}</p>
      <p>Stok: {stok()}</p>
      <button onClick={() => setStok(s => s - 1)} disabled={stok() === 0}>Beli 1</button>
    </div>
  )
}

Dengan CSS .habis { opacity: 0.5; filter: grayscale(1) } dan .sisa-sedikit { border-color: #f59e0b }, kartu Bumi Manusia (stok awal 2) berubah begini:

Kejadian stok() Atribut class
Halaman dibuka 2 kartu sisa-sedikit
Klik Beli 1 1 kartu sisa-sedikit
Klik Beli 1 lagi 0 kartu habis, kartunya abu-abu

Ini latihan pelajaran ini: sebuah <div>Konten</div> memakai classList={{ active: active() }}, signal-nya mulai dari true, dan tombol Toggle menjalankan setActive(v => !v). Klik pertama melepas kelas active, klik kedua memasangnya lagi.

style: objek dengan key kebab-case

style menerima objek. Key-nya nama properti CSS asli, kebab-case dalam kutip, persis seperti di file CSS:

<p style={{ "text-decoration": stok() === 0 ? "line-through" : "none", "font-size": "18px" }}>Rp{props.harga}</p>

class dan classList di elemen yang sama

Kartu dengan kelas tema yang dihitung, plus classList:

<div class={"kartu " + tema()} classList={{ habis: stok() === 0 }}>

Hasilnya di Solid 1.9, untuk Cantik Itu Luka (stok 0):

Kejadian Yang dijalankan Atribut class
Halaman dibuka className = "kartu terang", lalu toggle("habis", true) kartu terang habis
Tema diganti ke gelap className = "kartu gelap" kartu gelap

Kartunya gak abu-abu lagi, padahal stoknya masih 0. Itu jawaban tebakannya. class yang dihitung mengganti seluruh atribut dan ikut menghapus habis. classList cuma bertindak saat kondisinya sendiri berubah, dan stok() === 0 masih true seperti sebelumnya, jadi gak ada yang memasangnya lagi. Aturannya: kalau satu elemen memakai classList, biarkan class-nya tetap, dan pindahkan kelas yang berubah ke classList: class="kartu" classList={{ habis: stok() === 0, gelap: tema() === "gelap" }}.

CSS Modules: nama kelas yang gak bentrok

Kalau KartuBuku dan Keranjang sama-sama punya .judul di file CSS masing-masing, aturan yang dimuat belakangan menimpa yang lain, karena semua kelas CSS biasa berlaku di seluruh halaman. CSS Modules mencegahnya: file berakhiran .module.css diimpor sebagai objek, dan tiap nama kelasnya diganti jadi nama unik.

import styles from "./KartuBuku.module.css"

<div class={styles.kartu} classList={{ [styles.habis]: stok() === 0 }}>

Vite (bundler yang dipakai proyek Solid) mengganti .kartu jadi nama seperti _kartu_1x8p2_1, dan styles.kartu berisi nama itu. Jadi scope nama kelasnya otomatis per file. Ini fitur bundler, jadi berjalan di proyek Vite, bukan di Playground.

⚠️ Jebakan yang sering ketemu

TL;DR: class="kartu" untuk kelas tetap. classList={{ habis: stok() === 0 }} untuk kelas yang nyala-mati, satu classList.toggle per kelas, kondisinya ditulis sebagai pemanggilan. style={{ "text-decoration": "line-through", opacity: 0.5 }} dengan key kebab-case dalam kutip dan satuan di nilainya; backgroundColor dan "font-size": 20 dibuang browser. Jangan campur class yang dihitung dengan classList di satu elemen: tiap class berubah, kelas dari classList hilang. CSS Modules (import styles from "./KartuBuku.module.css") membuat nama kelas unik per file, jadi gak bentrok dengan komponen lain.

Yang akan kamu pelajari