Perbedaan antara Atribut HTML (Attributes) dan Properti DOM (Properties)
(jakearchibald.com)- Meski menempel pada elemen yang sama, atribut HTML dan properti DOM dapat berperilaku seperti ruang penyimpanan terpisah, sehingga perubahan di satu sisi tidak selalu otomatis tercermin di sisi lain
- Atribut terlihat dalam serialisasi HTML dan panel Elements di developer tools, tetapi properti adalah state khusus DOM, sehingga tidak muncul dalam hasil seperti
outerHTML - Nilai atribut selalu berupa string dan namanya tidak peka huruf besar-kecil, sedangkan properti dapat memiliki berbagai tipe seperti objek, dan namanya peka huruf besar-kecil
- Ada properti yang merefleksikan atribut seperti
id,className,htmlFor,ariaLabel, tetapi ada juga pengecualian sepertiinput.valueyang memisahkan state saat ini dan pengaturan default - Target yang disetel berbeda-beda menurut framework: Preact dan VueJS umumnya memprioritaskan properti, React umumnya memprioritaskan atribut, sedangkan Lit membedakan keduanya secara eksplisit dengan sintaks
.value
Atribut dan properti bisa berbeda meski namanya sama
- Atribut (attributes) dan properti (properties) dapat berperilaku seperti ruang penyimpanan yang berbeda
- Pada ``
getAttribute('foo')mengembalikan'bar', tetapidiv.foobisa sajaundefined - Setelah itu, meski menetapkan
div.foo = 'hello world', nilai atributfootetap'bar'
- Pada ``
- Dalam template framework, meski memakai sintaks yang terlihat seperti atribut, seperti ``, secara internal framework dapat menetapkan properti tergantung situasinya
- Kapan properti ditetapkan berbeda-beda menurut framework
- Beberapa pengaturan dapat menimbulkan efek samping yang mengubah properti sekaligus atribut
Yang tersisa dalam serialisasi HTML adalah atribut
- Atribut ada di HTML dan DOM, tetapi properti hanya ada di DOM
- Meski menjalankan
div.setAttribute('foo', 'bar')dandiv.hello = 'world',div.outerHTMLhanya menampilkan atribut, seperti `
`
- Panel Elements pada developer tools browser menampilkan atribut elemen, bukan seluruh propertinya
Tipe nilai dan penanganan huruf besar-kecil
- Nilai atribut harus bekerja dalam bentuk terserialisasi, sehingga selalu berupa string
- Jika objek dimasukkan dengan
setAttribute, objek tersebut disimpan sebagai string"[object Object]" - Jika objek yang sama dimasukkan ke properti, tipenya dapat tetap sebagai objek
- Jika objek dimasukkan dengan
- Nama atribut tidak peka huruf besar-kecil
HeLlO="world"dapat dinormalisasi menjadi atributhellodi DOMsetAttribute('FOO', 'bar')juga muncul sebagai atributfoo
- Nama properti peka huruf besar-kecil
- Meski menetapkan
div.TeSt = 'value',div.testbisa sajaundefined
- Meski menetapkan
- Berbeda dari nama atribut, nilai atribut peka huruf besar-kecil
Properti yang merefleksikan atribut
- Sebagian properti merefleksikan (reflect) atribut tertentu
div.idberperan sebagai getter/setter yang membaca dan menulis atributid- Jika menjalankan
div.id = 'bar', atributidjuga berubah menjadi'bar'
- Dalam relasi refleksi, atribut adalah sumber data
- Menetapkan properti akan memperbarui atribut
- Membaca properti akan membaca nilai atribut
- Atribut yang didefinisikan dalam spesifikasi sering dibuatkan properti padanannya demi kemudahan
- Atribut
foosembarang bukan atribut yang didefinisikan dalam spesifikasi, sehingga propertifooyang bersesuaian tidak otomatis muncul
- Atribut
- Spesifikasi `` mendefinisikan atribut di “Content attributes” dan properti di “DOM interface”
- Atribut IDL
reverseddantypeharus merefleksikan atribut konten dengan nama yang sama
- Atribut IDL
Relasi refleksi dengan nama yang berbeda
- Sebagian properti memiliki nama yang berbeda dari atribut yang direfleksikannya
- Ada kasus nama diubah agar sesuai dengan gaya properti JavaScript
el.crossOriginpada `` merefleksikan atributcrossoriginel.ariaLabelpada semua elemen merefleksikan atributaria-label- Properti refleksi ARIA menjadi lintas-browser pada akhir 2023; sebelumnya hanya atribut yang dapat digunakan
- Ada juga kasus nama diubah karena dulunya merupakan reserved word JavaScript
el.classNamepada semua elemen merefleksikan atributclassel.htmlForpada `` merefleksikan atributfor
Validasi, konversi tipe, dan nilai default
- Properti dapat memiliki validasi dan nilai default, tetapi atribut itu sendiri tidak memiliki perilaku seperti itu
input.typemenunjukkan perbedaan atribut dan properti dengan baik- Meski
input.getAttribute('type')adalahnull,input.typemengembalikan nilai default'text' input.type = 'number'terlihat seperti'number'baik pada atribut maupun propertiinput.type = 'foo'memasukkan'foo'ke atribut, tetapi getter properti melihat nilai yang tidak valid dan mengembalikan'text'
- Meski
- Sebagian properti melakukan konversi tipe
- Pada ``
details.getAttribute('open')adalah string kosong dandetails.openadalahtrue details.open = falsemenghapus atributopendetails.open = 'hello'tidak memasukkan string apa adanya ke atribut, melainkan mengonversinya menjadi boolean sehingga atributopenberada dalam keadaan ada
- Pada ``
- Properti seperti
img.heightmengonversi nilai atribut menjadi angka- Setter mengubah nilai yang masuk menjadi angka, dan memperlakukan angka negatif sebagai 0
input.value memisahkan nilai saat ini dan nilai default
- Pada
inputada propertivaluedan atributvalue, tetapi propertivaluetidak merefleksikan atributvalue - Properti yang merefleksikan atribut
valueadalahdefaultValue- Getter
defaultValuemengembalikan atributvalueatau string kosong - Setter
defaultValuemenetapkan atributvaluesebagai string
- Getter
- Properti
valueawalnya mengikutidefaultValue, lalu setelah ditetapkan lewat JavaScript atau interaksi pengguna, ia menggunakan nilai internal- Pada `` awal,
value,defaultValue, dangetAttribute('value')semuanya adalah'default' - Jika menjalankan
input.defaultValue = 'new default', atribut danvaluesama-sama terlihat seperti'new default' - Setelah itu, jika menjalankan
input.value = 'hello!',valuemenjadi'hello!', tetapi atribut dandefaultValuetetap'new default' - Meski menjalankan
setAttribute('value', 'another new default'),valuesaat ini tetap'hello!'
- Pada `` awal,
- Saat form di-reset, perilakunya bisa berupa pengaturan ulang state internal
value
Atribut lebih alami untuk pengaturan, properti untuk state
- Pembedaan bahwa atribut digunakan untuk pengaturan (configuration) dan properti untuk state terasa alami
- `` adalah contoh yang sesuai dengan pembedaan ini, kecuali dari sisi penamaan
- Atribut
valuemenetapkan nilai default - Properti
valuemenyediakan state saat ini
- Atribut
- Validasi diterapkan saat membaca atau menulis properti, dan tidak diterapkan saat membaca atau menulis atribut; pembedaan ini juga cocok dengan cara pandang tersebut
danmerepresentasikan keadaan terbuka dengan atributopen, dan browser secara langsung menambahkan atau menghapus atribut ini sesuai interaksi pengguna- Desain ini merusak pembedaan bahwa atribut adalah untuk pengaturan
- Framework yang memelihara DOM atau kode JavaScript biasa perlu siap menghadapi situasi ketika DOM berubah sendiri
- Desain alternatif dapat membaginya menjadi atribut pengaturan default seperti ``, properti
details.openuntuk membaca dan menulis state saat ini, serta pseudo-class CSS untuk menargetkan state - Simon Peters menemukan diskusi desain awal terkait hal ini
contenteditablejuga merusak pembedaan ini, tetapi diperlakukan sebagai opt-in yang menerima banyak kerusakan
Cara penanganan di tiap framework
- Preact dan VueJS, kecuali beberapa pengecualian yang telah didefinisikan sebelumnya, menetapkan properti ketika
propName in elementbernilai benar, dan jika tidak, menetapkan atribut- Secara default, mereka lebih memilih properti daripada atribut
- Metode rendering string bekerja sebaliknya, dan item yang hanya berupa properti diabaikan
- Implementasi terkait:
setPropertydi Preact,shouldSetAsPropdi VueJS
- React menetapkan atribut, kecuali beberapa pengecualian yang telah didefinisikan sebelumnya
- Cara ini membuat logikanya mirip dengan metode rendering string
- Karena properti custom element tidak ada dalam daftar yang telah didefinisikan React, properti tersebut ditetapkan sebagai atribut, dan API yang hanya berupa properti mungkin tidak berfungsi
- Pada React 19, untuk custom element, React akan beralih ke model Preact/VueJS
- React memopulerkan nama properti
classNamedalam sintaks yang terlihat seperti atribut, tetapi secara internal menetapkan atributclass - Implementasi terkait:
setPropdi React
- lit-html mempertahankan perbedaan antara atribut dan properti lewat sintaks
- Jika menambahkan
.di depan nama seperti ``, yang ditetapkan adalah properti, bukan atribut - Dokumentasi terkait: Lit expressions
- Jika menambahkan
3 komentar
Komentar Hacker News
Atribut data-* menjadi kompromi yang cukup baik di antara pendekatan yang dibahas dalam artikel
Atribut ini otomatis diekspos di JavaScript sebagai properti baca/tulis pada
dataset, sehingga bisa diakses sepertidocument.getElementById('myDiv').dataset.payload == "something"Hanya saja, atribut HTML memakai
kebab-casesedangkan JavaScript memakaicamelCase, jadi perlu hati-hati karenadata-my-cool-data-attributemenjadidataset.myCoolDataAttributeDi berbagai ekosistem yang memakai
camelCase, tidak ada konvensi mapan untuk menangani singkatan berhuruf besar, jadi kasus sepertidataset.myIDmenjadi serba tanggungElement.hasAttribute('data-thing'),Element.getAttribute('data-thing'),Element.setAttribute('data-thing', '...')untuk menghindari konversi antarakebab-casedancamelCaseSaat memeriksa atau debugging di DOM, kita jadi tidak perlu melewati konversi aneh, sehingga maksudnya jauh lebih jelas
Selain itu, https://developer.mozilla.org/en-US/docs/Web/HTML/Global_att... menjelaskan atribut global
data-*sebagai “atribut data kustom yang memungkinkan pertukaran informasi proprietary antara HTML dan representasi DOM-nya oleh skrip”Konteks yang dimaksud di sini tidak harus berarti
iframeyang berbeda, tetapi juga kasus seperti ekstensi browser yang membuat konteks eksekusi JavaScript terpisah namun tetap bisa mengakses DOM yang samaDalam istilah protokol developer tools, hal seperti ini juga disebut isolated worlds
Hal-hal yang dibahas artikel ini menunjukkan kompleksitas dan perilaku yang tidak banyak membantu dalam kehidupan nyata
Perilaku seperti ini hanya punya kekurangan tanpa kelebihan, dan spesifikasinya seharusnya cukup mendefinisikan objek DOM dan objek JavaScript sebagai hal yang sama, sehingga atribut dan properti juga menjadi konsep yang sama
Bisa menyimpan nilai non-string pada node DOM adalah kelebihan yang jelas, dan bukan hal yang bisa disepelekan
Ini sama sekali tidak sederhana kecuali semua properti diwajibkan hanya berupa string
Kita juga harus memikirkan konversi dengan angka, properti yang bisa diisi objek, dan properti yang tidak punya pasangan atribut
Meski begitu, akan lebih baik jika ada konvensi atau aturan yang 100% tetap, tetapi itu bukan hal yang sederhana
Metode seperti
addEventListeneradalah properti prototipe dari elemen DOM individual, tetapi tidak masuk akal jika dipandang sebagai atribut stringKalau begitu, metode elemen DOM harus menjadi fungsi bebas seperti
HTMLElement.addEventListener(foo, 'some-event', e => console.log(e));; ini soal selera, tetapi enak juga bisa memakai pemanggilan metode objek di JavaScriptElemen DOM punya antarmuka yang sangat spesifik untuk mengubah state lewat
setAttribute, dan ketika seseorang hanya menempelkan properti ke objek JavaScript yang dibuat untuk mengirim pesan ke DOM lewat antarmuka itu, kenapa kita harus berharap itu akan otomatis dirutekan?Mungkin API seperti itu akan memberi pengalaman yang lebih baik, tetapi ada beberapa tantangan, walaupun rasanya memang akan lebih rapi
Mungkin karena saya terlalu lama menulis kode backend, ketika melihat antarmuka seperti ini rasanya ada banyak hal aneh terjadi di balik layar, seolah ada pengembang baik hati di masa lalu yang memberi wrapper paling aman yang mungkin
Sudut pandang yang membantu untuk memahami ini adalah bahwa atribut dalam arti sempit adalah node DOM, yaitu node
AttrNode ini bisa punya properti seperti
name,value,ownerElement,prefix, dan secara keseluruhan dapat diakses sebagai nilai propertiattributesmilik elemen pemiliknya dalam bentukNamedNodeMap, bukan arrayKarena itu, nama
getAttribute(name)agak menyesatkan; sebenarnya ia tidak mengembalikan node atribut itu sendiri, melainkan propertivaluedari node atribut tersebut, jadi lebih dekat kegetAttributeValue(name)Referensi: https://developer.mozilla.org/en-US/docs/Web/API/Element/get..., https://developer.mozilla.org/en-US/docs/Web/API/Element/get..., https://developer.mozilla.org/en-US/docs/Web/API/Attr
el.attributes, dan tidak bisa dilakukan lewatsetAttribute,getAttribute,getAttributeNames,hasAttributeNode atribut juga tidak bisa dipindahkan antar elemen, dan urutan node atribut di dalam elemen pun tidak bisa diubah
Jake, lalu bagaimana dengan ini: https://jakearchibald.com/2023/against-self-closing-tags-in-...
Saya paham logika untuk tidak memperbarui properti, tetapi fakta bahwa target bisa dipilih dengan CSS itu berguna
:checkedpada elemen inputJauh lebih mudah untuk debugging dengan langsung memeriksa DOM daripada harus melewati debugger
Mungkin perbedaan yang paling penting adalah persistensi, tetapi ini tidak dibahas dalam artikelnya
Atribut tetap ada selama kita masih bisa mengakses root object yang sama dari pohon DOM tersebut, misalnya selama belum meninggalkan halaman
Properti objek hanya bertahan sampai objek itu di-garbage collect
Jika node DOM dikloning atau melalui serialisasi/deserialisasi, itu menjadi node DOM yang sepenuhnya berbeda dengan atribut yang sama, sehingga tidak lagi memiliki properti yang bukan nilai default dari node lain
Tulisan yang menarik
Saya selalu melihat elemen DOM di JavaScript seperti proxy
Itu memungkinkan kita bekerja dengan elemen DOM yang sebenarnya, tetapi pada saat yang sama itu juga hanya objek JavaScript, jadi rasanya kita bisa menetapkan nilai dan melakukan hal yang kita mau selain memakai fungsi-fungsi yang berinteraksi dengan elemen aslinya
Penjelasannya enak dibaca karena dipaparkan dengan contoh, dan terutama karena ada beberapa detail yang sering mudah terlewat, ini tampaknya bisa membantu banyak orang
Properti DOM juga disebut IDL attributes
Di luar para penulis spesifikasi, jarang ada orang yang menyebutnya
IDL attributes, dan kalau keduanya sama-sama disebut attribute itu jadi sangat membingungkanTulisan yang bagus, dan ini membuat saya penasaran seperti apa bentuk cara representasi yang lebih baik
Akan menarik jika HTML bisa memiliki atribut yang bukan string, dan nilainya merujuk ke nilai lokal dari tag
scriptyang memiliki scopePerspektif yang melihat atribut sebagai konfigurasi default terasa agak aneh
Misalnya, jika atribut
classhanya menampilkan nilai default, saat class di-toggle maka class yang aktif tidak akan terlihat di DOM inspector atau HTML yang diserialkan, atau class yang nonaktif justru akan terlihat, dan itu akan terasa cukup anehAtribut
classbekerja dengan baik dalam sistem iniSaya sebagai pemilik dokumen menetapkan atribut
class, dan seiring waktu saya bisa mengubah konfigurasi itu, tetapi hanya saya yang melakukannyaDalam sistem alternatif, browser akan menambah dan menghapus class sendiri sebagai respons terhadap status hover atau focus, tetapi untungnya itu tidak begitu, dan yang dipakai adalah pseudo-class
https://emewjin.github.io/html-attribute-dom-property/
attribute dan property sama-sama diterjemahkan sebagai "atribut" ya..