Di Vue, data bisa menentukan class dan gaya inline sebuah elemen lewat :class dan :style, dan <style scoped> menjaga CSS sebuah komponen supaya gak bocor ke komponen lain. Bayangin papan menu Warung Bu Sri. Waktu pembeli memilih sebuah menu, Bu Sri menjepitkan penanda kuning di kartunya. Waktu menu habis, kartunya dicoret abu-abu. Penanda itu datang dan pergi mengikuti keadaan, persis class yang dipasang :class. Dan cat papan Bu Sri diberi label "khusus Warung Bu Sri", supaya tukang cat gak ikut mengecat papan warung sebelah dengan warna yang sama: itu scoped.
🧪 Tebakan cepat:
pilihanberisi"Mie Ayam", dan stok Mie Ayam 0. Baris menunya ditulis<li class="item" :class="{ dipilih: m.nama === pilihan, habis: m.stok === 0 }">. Atributclassapa yang dipasang di baris Mie Ayam? Tebak dulu, jawabannya ada di bagian ":class dengan object".
:class dengan object
const pilihan = ref("Mie Ayam")
const menu = ref([
{ id: 1, nama: "Nasi Goreng", stok: 5 },
{ id: 2, nama: "Mie Ayam", stok: 0 },
{ id: 3, nama: "Es Teh", stok: 10 },
])
---template---
<ul>
<li
v-for="m in menu"
:key="m.id"
class="item"
:class="{ dipilih: m.nama === pilihan, habis: m.stok === 0 }"
@click="pilihan = m.nama"
>
{{ m.nama }}
</li>
</ul>
Hasil render-nya:
<ul>
<li class="item">Nasi Goreng</li>
<li class="item dipilih habis">Mie Ayam</li>
<li class="item">Es Teh</li>
</ul>
Baris Mie Ayam mendapat class="item dipilih habis". Itu jawaban tebakannya.
:classadalahv-bind:class, v-bind yang sama dari pelajaran template.- Dalam object, nama properti adalah nama class, dan nilainya syarat. Class dipasang kalau syaratnya truthy, dan dilepas kalau falsy. Klik Nasi Goreng, dan
dipilihpindah ke sana. classbiasa dan:classboleh dipakai bersamaan. Vue menggabungkan keduanya, jadiitemselalu ada.- Jadi
:class="{ active: isActive, error: hasError }"denganisActivetruedanhasErrorfalsecuma memasangactive. - Latihan kedua:
<div id="status" :class="{ active: isActive }">Online</div>, denganisActivebernilaitrue. - Nama class yang memakai tanda minus wajib dikutip:
{ 'stok-habis': m.stok === 0 }. Tanpa kutip, template gagal di-compile denganUnexpected token '-', dan komponennya gak tampil.
:class dengan array
const ukuran = ref("besar")
const dipilih = ref(true)
---template---
<p :class="['kartu', ukuran, { dipilih: dipilih }]">Nasi Goreng</p>
Hasilnya <p class="kartu besar dipilih">.
- Tiap isi array adalah nama class: teks tetap seperti
'kartu', nilai dari data sepertiukuran, atau object bersyarat di dalamnya. - Ternary juga bisa,
:class="dipilih ? 'dipilih' : ''", tapi cepat panjang. Object lebih rapi untuk class yang datang dan pergi.
:style: gaya inline dari data
const warna = ref("#b45309")
const besar = ref(18)
---template---
<p :style="{ color: warna, fontSize: besar + 'px', 'font-weight': 700 }">Promo hari ini</p>
Hasilnya <p style="color: rgb(180, 83, 9); font-size: 18px; font-weight: 700;">.
- Nama properti CSS ditulis camelCase (
fontSize) atau kebab-case dalam kutip ('font-size'). - Vue gak menambahkan satuan.
{ padding: 20 }gak menghasilkan apa-apa, karena20tanpapxbukan nilai CSS yang sah. Tulis{ padding: '20px' }. Angka tanpa satuan cuma cocok untuk properti yang memang tanpa satuan, sepertiopacity,zIndex,lineHeight,fontWeight. stylebiasa dan:stylejuga digabung.- Latihan pertama:
<div id="box" :style="{ color: color, padding: '20px' }">Kotak Biru</div>, dengancolorberisi"blue". Kotaknya biru dan punya padding 20px. - Pakai
:classuntuk keadaan yang sudah dirancang di CSS (dipilih, habis, aktif). Pakai:styleuntuk nilai yang benar-benar datang dari data, misalnya warna pilihan pengguna atau lebar bar stok dalam persen.
Scoped styles di file .vue
<!-- MenuList.vue -->
<script setup>
import { ref } from "vue"
const pilihan = ref("Mie Ayam")
</script>
<template>
<h3 class="judul">Menu</h3>
<p class="item" :class="{ dipilih: pilihan === 'Mie Ayam' }">Mie Ayam</p>
</template>
<style scoped>
.judul { color: #b45309; }
.dipilih { background: #fef3c7; }
</style>
Yang dihasilkan build-nya, kira-kira:
<h3 data-v-7a3f2c1e="" class="judul">Menu</h3>
<p data-v-7a3f2c1e="" class="item dipilih">Mie Ayam</p>
.judul[data-v-7a3f2c1e] { color: #b45309; }
.dipilih[data-v-7a3f2c1e] { background: #fef3c7; }
scopedmemberi setiap elemen di komponen itu atributdata-v-ditambah kode unik milik komponen tersebut, lalu menulis ulang tiap selector supaya hanya mengenai elemen yang membawa atribut itu.- Jadi
<p class="judul">diWarungFooter.vuegak ikut berwarna oranye, karena atributnya beda. Tanpascoped,.judul { color: #b45309; }berlaku untuk seluruh halaman. - Kodenya (
7a3f2c1edi sini cuma contoh) dibuat oleh build. Jangan ditulis sendiri. - Editor latihan gak punya tempat untuk
<style>.<style>yang ditaruh di template dibuang diam-diam oleh Playground (build production); build development menulis[Vue warn]: Template compilation error: Tags with side effect (<script> and <style>) are ignored in client component templates.Kode Playground di Lab memasang CSS-nya lewat script supaya warnanya kelihatan.
⚠️ Jebakan yang sering ketemu
- Angka tanpa satuan di
:style.{ padding: 20 }diabaikan begitu saja, tanpa error. Latihan pertama memeriksa padding20px, jadi tulis'20px'. - Lupa titik dua.
class="{ active: isActive }"tanpa:dipasang sebagai teks apa adanya, bukan dihitung. Latihan memeriksa:classdan:style. - Nama class bertanda minus tanpa kutip.
{ stok-habis: ... }membuat template gagal di-compile. Tulis{ 'stok-habis': ... }. - CSS tanpa
scopeddi komponen. Selector umum seperti.judulataupikut mengubah komponen lain di halaman yang sama.
TL;DR: :class="{ dipilih: m.nama === pilihan }" memasang class saat syaratnya benar dan melepasnya saat salah; array seperti ['kartu', ukuran, { dipilih }] menggabungkan beberapa class, dan class biasa ikut digabung. :style="{ color: color, padding: '20px' }" memasang gaya inline dari data, nama propertinya camelCase, dan Vue gak menambahkan px, jadi angka butuh satuannya. <style scoped> di file .vue memberi elemen komponen atribut data-v-... dan menulis ulang selector-nya, jadi CSS komponen itu gak bocor ke komponen lain.