Atribut yang kamu tulis di tag sebuah komponen tapi bukan prop, misalnya class, id, style, type, atau @click, otomatis diteruskan ke root element komponen itu, yaitu elemen paling luar di template-nya. Vue menyebutnya fallthrough attributes. Bayangin kasir Warung Bu Sri menempel stiker "PEDAS" di pesanan bungkus. Stikernya nempel di kertas pembungkus paling luar, bukan di nasinya. Kalau pesanannya dua bungkus yang terpisah, kasir bingung harus menempel di yang mana, jadi stikernya gak ditempel sama sekali.
🧪 Tebakan cepat: Template komponen
Tombolcuma berisi<button class="tombol">Pesan</button>. Parent menulis<Tombol class="utama" id="pesan" />. HTML apa yang keluar? Tebak dulu, jawabannya ada di bagian "Atribut jatuh ke root element".
Atribut jatuh ke root element
<!-- Tombol.vue -->
<template>
<button class="tombol" type="button">Pesan</button>
</template>
<!-- App.vue -->
<Tombol class="utama" id="pesan" type="submit" style="color: white" @click="pesan" />
HTML yang keluar:
<button class="tombol utama" type="submit" id="pesan" style="color: white;">Pesan</button>
classdigabung: milik child dulu, lalu milik parent, jaditombol utama. Itu jawaban tebakannya, ditambahid="pesan".stylejuga digabung. Kalau properti yang sama ditulis dua-duanya, nilai dari parent yang menang.- Atribut lain, seperti
id,type,disabled, ataudata-menu, menimpa:type="submit"dari parent menggantitype="button"milik child. - Listener seperti
@clickdipasang di root element. Klik tombolnya, fungsipesanmilik parent jalan. - Yang sudah dinyatakan sebagai prop atau di
emitsgak ikut diteruskan, karena sudah dipakai komponennya sendiri.
$attrs: semua yang diteruskan
Semua atribut yang diteruskan dikumpulkan di objek $attrs. Di template child, {{ $attrs }} untuk tag tadi berisi class, id, type, style, dan onClick. Di <script setup>, objek yang sama didapat dengan useAttrs() yang di-import dari "vue".
Mematikan pewarisan: inheritAttrs: false
Kadang root element bukan tempat yang tepat. Misalnya Tombol membungkus tombolnya dengan <div>, dan class atau id dari parent seharusnya jatuh ke <button>, bukan ke <div>:
<!-- Tombol.vue -->
<script setup>
defineOptions({ inheritAttrs: false })
</script>
<template>
<div class="bungkus">
<button v-bind="$attrs">Pesan</button>
</div>
</template>
Hasilnya untuk <Tombol class="utama" id="pesan" @click="pesan" />:
<div class="bungkus"><button class="utama" id="pesan">Pesan</button></div>
inheritAttrs: falsemenyuruh Vue berhenti menempelkan atribut ke root element.v-bind="$attrs"menempelkan semuanya, termasuk listener@click, ke elemen yang kamu pilih.defineOptionstersedia di<script setup>sejak Vue 3.3.
Banyak root: gak ada yang dapat
<!-- Tombol.vue, dua root -->
<template>
<button>Pesan</button>
<small>Habis jam 9</small>
</template>
<Tombol class="utama" id="pesan" /> menghasilkan <button>Pesan</button><small>Habis jam 9</small> tanpa class dan id. Vue gak tahu harus menempel di root yang mana, jadi gak menempel sama sekali. Build development menulis [Vue warn]: Extraneous non-props attributes (class, id) were passed to component but could not be automatically inherited because component renders fragment or text or teleport root nodes. Obatnya: tulis v-bind="$attrs" di root yang harus menerimanya, dan warning-nya hilang.
File .vue dan editor latihan
Di editor, child ditulis sebagai objek dan dipasang dengan <component :is>. Atribut yang kamu tulis di <component> diteruskan dengan cara yang sama:
const jumlah = ref(0)
const Tombol = {
template: `<button class="tombol">Pesan</button>`,
}
---template---
<div>
<component :is="Tombol" class="utama" id="pesan" @click="jumlah++" />
<p>Dipesan: {{ jumlah }}</p>
</div>
| Di file .vue | Di editor latihan |
|---|---|
defineOptions({ inheritAttrs: false }) |
opsi inheritAttrs: false di objek Tombol |
useAttrs() di script |
$attrs di template child |
<Tombol class="utama" /> |
<component :is="Tombol" class="utama" /> |
Latihannya memakai bentuk ini. Starter-nya punya Tombol dengan template <button class="btn">Klik Saya</button>, tanpa id, dan kamu memasangnya dengan <component :is="Tombol" id="btn" class="primary" />. id itu jatuh ke <button>, dan primary digabung dengan btn. Pemeriksanya membaca button#btn.btn.primary, dan menolak id yang ditulis langsung di <button>.
⚠️ Jebakan yang sering ketemu
- Mengira
classdari parent menimpa milik child.classdanstyledigabung. Yang menimpa itu atribut lain sepertiiddantype. - Atribut jatuh ke pembungkus. Kalau root-nya
<div>,iddan@clickmendarat di<div>. PakaiinheritAttrs: falsedanv-bind="$attrs"di elemen yang benar. - Komponen banyak root yang diam-diam membuang atribut. Tanpa
v-bind="$attrs", atributnya hilang, dan warning-nya cuma muncul di build development. - Teks tombol gak persis. Latihan memeriksa teks
Klik Saya, dengan K dan S besar.
TL;DR: Atribut di tag komponen yang bukan prop atau emits, seperti class, id, style, dan @click, diteruskan ke root element komponen itu. class dan style digabung, atribut lain dari parent menimpa milik child, dan listener ikut dipasang. Semuanya terkumpul di $attrs (useAttrs() di script). inheritAttrs: false mematikan penerusan otomatis, lalu v-bind="$attrs" menempelkannya ke elemen pilihanmu. Komponen dengan banyak root gak meneruskan apa pun sampai kamu menulis v-bind="$attrs" sendiri.