Kısa cevap: data- ile başlayan her öznitelik bir özel veri özniteliğidir (custom data attribute). Bir HTML öğesine, görünür bir anlamı olmayan ama betiklerin ihtiyaç duyduğu ek bilgiyi, standart dışı öznitelik uydurmadan eklemenizi sağlar: <li data-paket-id="101">. JavaScript'te bu değerlere öğenin dataset özelliğiyle erişirsiniz; data- öneki atılır ve kalan ad camelCase biçimine çevrilir, yani data-paket-id değeri dataset.paketId olur. Tüm değerler dizgedir.

MDN'e göre data-* öznitelikleri, HTML ile onun DOM temsili arasında betiklerin kullanabileceği özel bilgi alışverişi için vardır. Bu yazıda adlandırma kurallarını, dataset dönüşümünün inceliklerini, CSS'ten erişimi, sınıflarla karşılaştırmayı ve MDN'in "kullanmayın" dediği durumları anlatıyoruz. Diğer global öznitelikler için global öznitelikler rehberine, tarih ve ürün kodu gibi görünen metnin makine okunur karşılığını veren <data> öğesi için time ve data etiketi yazısına bakabilirsiniz.

Sözdizimi: Adı data- ile başlayan her öznitelik

Kural basittir: Herhangi bir öğede adı data- ile başlayan her öznitelik bir veri özniteliğidir. MDN'in örneğinde bir listedeki makaleler, görsel bir karşılığı olmayan ek bilgiler taşır: kaç sütunda gösterileceği, bir dizin numarası ve üst kategori. Bu bilgiler sayfada görünmez, ama betikler onları okuyabilir.

html
<main>
  <article id="elektrikli-araclar" data-columns="3" data-index-number="12314" data-parent="cars">
    <h2>Elektrikli araçlar</h2>
  </article>
  <article id="gunes-araclari" data-columns="3" data-index-number="12315" data-parent="cars">
    <h2>Güneş enerjili araçlar</h2>
  </article>
</main>

Veri öznitelikleri global öznitelik olduğu için her öğede kullanılabilir; <li>, <img>, <button> ya da <tr> fark etmez. MDN bunun gücünü bir oyun örneğiyle anlatır: Bir uzay gemisi görseli, yalnızca bir <img> öğesi, bir class ve birkaç data-* özniteliğiyle gemi kimliği, silahlar, kalkan durumu ve koordinatlar gibi bilgileri taşıyan bir program nesnesine dönüşebilir.

html
<img class="gemi" src="gemi.png" alt="Uzay gemisi"
     data-ship-id="324" data-weapons="laserI laserII" data-shields="72%">

Adlandırma kuralları

Adlandırma kuralları: Ad xml ile başlamamalıdır (büyük-küçük harf fark etmeksizin); bu önek..., Ad iki nokta üst üste (:) içermemelidir; XML bu tür adlara anlam yükler., Ad büyük...

Yıldız işaretinin yerine gelen ad, XML adlarının üretim kuralına uymalıdır. MDN bunun yanında üç öneri sıralar:

  • Ad xml ile başlamamalıdır (büyük-küçük harf fark etmeksizin); bu önek gelecekteki XML spesifikasyonları için ayrılmıştır.
  • Ad iki nokta üst üste (:) içermemelidir; XML bu tür adlara anlam yükler.
  • Ad büyük harf içermemelidir; XML tamamen küçük harflidir.

Bunlar öneridir, uyulmadığında hata oluşmaz. MDN, bu önerilere uymayan özniteliklerin de CSS öznitelik seçicileriyle eşleştirildiğini ve dataset tarafından tanındığını belirtir. CSS eşleşmesinde öznitelik adı büyük-küçük harfe duyarsızdır, değer ise duyarlıdır. Yani data-Durum="Aktif" yazmak çalışır, ama kodu okuyanın kafasını karıştırır; küçük harfli ve kısa çizgili adlar en güvenli seçimdir.

dataset: Öznitelik adından JavaScript özelliğine

Her öğenin HTMLElement arayüzü üzerinden tüm özel verilere erişilebilir; erişim yolu dataset özelliğidir ve bir DOMStringMap döndürür. Dönüşüm şöyle işler: data- öneki kaldırılır, kalan ad kebab-case'den camelCase'e çevrilir. element.getAttribute("data-test") ile element.dataset.test eşdeğerdir; data-test-abc ise dataset.testAbc ya da dataset["testAbc"] ile okunur.

javascript
const makale = document.querySelector("#elektrikli-araclar");
makale.dataset.columns; // "3"
makale.dataset.indexNumber; // "12314"
makale.dataset.parent; // "cars"

Bu dönüşümün bir sonucu vardır: dataset kullanacaksanız data- sonrasındaki ad yalnızca JavaScript özellik adlarında izin verilen karakterleri (ve atılacak kısa çizgileri) içermelidir. MDN, kısa çizgiden sonra harf olmayan bir karakter gelmesinden kaçınmayı önerir: data-test-1 ya da data--test gibi adlar dataset tarafından tanınmaz. Bu durumda değere yalnızca getAttribute() ile ulaşabilirsiniz.

HTML özniteliğidataset ile erişim
data-columnsdataset.columns
data-index-numberdataset.indexNumber
data-paket-iddataset.paketId
data-test-1Tanınmaz, getAttribute kullanın
data--testTanınmaz, getAttribute kullanın

Değerler her zaman dizgedir

Değerler her zaman dizgedir

dataset üzerindeki her özellik bir dizgedir ve hem okunabilir hem yazılabilir. MDN'in örneğinde article.dataset.columns = 5 ataması özniteliği "5" olarak değiştirir. Yani sayı yazsanız bile HTML'e dizge olarak döner; okuduğunuzda da dizge alırsınız. Hesap yapacaksanız değeri JavaScript'te açıkça sayıya çevirmeniz gerekir. Bu dönüşümün ayrıntıları için JavaScript öğrenme rehberine bakabilirsiniz.

javascript
makale.dataset.columns = 5;
// Öznitelik artık data-columns="5" olur

Veri özniteliklerine göre öğe aramak da mümkündür. document.querySelector() ve document.querySelectorAll() öznitelik seçicileriyle çalışır: [data-columns] bu özniteliği taşıyan tüm öğeleri, [data-columns="3"] ise değeri tam olarak 3 olanları bulur.

javascript
const hepsi = document.querySelectorAll("[data-columns]");
const ucSutunlu = document.querySelectorAll('[data-columns="3"]');
ucSutunlu.forEach((m) => {
  console.log(m.dataset.indexNumber);
});

CSS'ten erişim

Veri öznitelikleri sıradan HTML öznitelikleri olduğu için CSS de onlara erişebilir: Oluşturulan içerikte attr() işleviyle değeri gösterebilir ya da öznitelik seçicileriyle değere göre stil verebilirsiniz. MDN bir ayrıntıyı hatırlatır: Veri değerleri dizge olduğu için sayısal değerler seçicide tırnak içinde yazılmalıdır, aksi halde stil uygulanmaz. Seçici ve stil ayrıntıları bu yazının konusu değildir; görünüm her zaman CSS tarafında çözülür.

Sınıf mı, veri özniteliği mi?

MDN, bir bileşenin farklı görünümlerini (varyantlarını) yönetmek için sınıflara alternatif olarak veri özniteliklerini gösterir. Geleneksel yöntemde her varyant ayrı bir sınıftır:

html
<div class="bilgi bilgi--not">...</div>
<div class="bilgi bilgi--uyari">...</div>

Veri özniteliğiyle aynı şey tek bir öznitelikte ifade edilir:

html
<div class="bilgi">...</div>
<div class="bilgi" data-variant="not">...</div>
<div class="bilgi" data-variant="uyari">...</div>

MDN bu yaklaşımın üç avantajını sayar. Birincisi, birçok geçersiz durumu ortadan kaldırır: Varyant sınıfını temel sınıf olmadan eklemek ya da aynı anda iki varyant uygulamak gibi. İkincisi, ayrı bir data-variant özniteliği, geçerli değerlerin lint ya da tip denetimi gibi statik analiz araçlarıyla kontrol edilmesine olanak verir. Üçüncüsü, varyantı değiştirmek daha sezgiseldir: classList üzerinde birkaç adım yerine tek bir div.dataset.variant = "uyari" ataması yeterlidir.

Veriyi öğenin yanında tutmak

MDN, birçok web uygulamasında arayüz durumunun asıl kaynağının JavaScript verisi olduğunu ve bu durumda HTML'e yalnızca görüntüleme için gereken özniteliklerin eklendiğini belirtir. Veri öznitelikleri ise tersi durumda işe yarar: Her şey zaten işaretlemede vardır ve JavaScript yalnızca olayları yönetmek, durumu senkronize etmek gibi davranışlar için gerekir. MDN'in örneğinde çok sayıda görsel içeren bir kaydırmalı galeride, her görselin kaynağı başlangıçta data-src içinde tutulur; böylece hiçbir istek gönderilmez. Görsel görünür alana girdiğinde gerçek src değeri betikle eklenir. Veri öğenin yanında durur, JavaScript yalnızca davranışı tanımlar. Yerel tembel yükleme için <img> öğesinin kendi loading özniteliği de vardır; bkz. img etiketi yazısı.

Uygulamalı mini örnek: Paket karşılaştırma listesi

Aşağıdaki listede her paket, sepete ekleme betiğinin ihtiyaç duyduğu kimliği ve dönem bilgisini veri özniteliklerinde taşır. Görünen bilgi ise normal metindir; ekran okuyucular ve arama motorları onu okuyabilir.

html
<ul>
  <li data-paket-id="101" data-donem="yillik">
    Başlangıç Paketi
    <button type="button" data-islem="sepete-ekle">Sepete ekle</button>
  </li>
  <li data-paket-id="102" data-donem="aylik">
    Profesyonel Paket
    <button type="button" data-islem="sepete-ekle">Sepete ekle</button>
  </li>
</ul>
javascript
document.querySelectorAll('[data-islem="sepete-ekle"]').forEach((dugme) => {
  dugme.addEventListener("click", () => {
    const satir = dugme.closest("li");
    console.log(satir.dataset.paketId, satir.dataset.donem);
  });
});

Burada üç şeye dikkat edin. Öznitelik adları küçük harfli ve kısa çizgilidir, kısa çizgilerden sonra hep harf gelir; bu yüzden dataset.paketId sorunsuz çalışır. Paket adı veri özniteliğine değil, görünen metne yazılmıştır. Düğmeler gerçek <button> öğeleridir; veri özniteliği yalnızca hangi işlemi yapacaklarını söyler, etkileşimi sağlamaz.

Ne zaman kullanmamalı?

Ne zaman kullanmamalı? Betik için ek bilgi, Stil grubu, Belgede tek öğeyi belirlemek, Görünen metnin makine okunur karşılığı

MDN'in "Issues" bölümü kısa ama nettir: Görünür ve erişilebilir olması gereken içeriği veri özniteliklerinde saklamayın, çünkü yardımcı teknolojiler bunlara erişemeyebilir. Ayrıca arama motoru tarayıcıları veri özniteliklerinin değerlerini dizine eklemeyebilir. Bir değeri yalnızca göstermek istiyorsanız MDN, onu doğrudan öğenin metnine (textContent) yazmanın genellikle daha iyi olduğunu belirtir.

İhtiyaçDoğru araç
Betik için ek bilgidata-* öznitelikleri
Stil grubuclass
Belgede tek öğeyi belirlemekid
Görünen metnin makine okunur karşılığıdata öğesi
Tarih ve saatin makine okunur değeritime öğesi
Kullanıcının görmesi gereken bilgiGörünür metin
Arama motorları için yapılandırılmış veriJSON-LD veya mikroveri

Yapılandırılmış veri ayrı bir konudur ve veri öznitelikleri bunun yerine geçmez; ayrıntılar için schema.org ve JSON-LD yazısına bakabilirsiniz.

Tablodaki ayrımların en çok karıştırılanı data-* öznitelikleri ile <data> öğesidir. Adları benzer olsa da görevleri farklıdır. <data> öğesi, sayfada görünen bir metnin (örneğin bir ürün adının) makine okunur çevirisini value özniteliğinde taşır; yani öğenin içeriği ile değeri aynı şeyin iki farklı yüzüdür. data-* öznitelikleri ise herhangi bir öğeye, içeriğiyle doğrudan ilişkili olması gerekmeyen ek bilgiler ekler: bir sütun sayısı, bir kategori, bir işlem adı. İkincisi bir anlam bildirmez, yalnızca betikler için bir taşıyıcıdır.

Sınıflarla karşılaştırma da benzer bir mantık izler. class bir öğeyi bir gruba dahil eder ve çoğunlukla CSS ile JavaScript'in öğeleri seçmesi için kullanılır; değerleri bir küme gibidir, sıraları ve sayıları önemli değildir. Veri özniteliği ise bir ad ve tek bir değer çiftidir: data-variant="uyari" aynı anda yalnızca bir değer alabilir. MDN'in varyant örneğinde geçersiz durumların azalmasının nedeni budur; bir öğede aynı anda iki data-variant olamaz, ama iki varyant sınıfı olabilir.

Bir veri özniteliği tasarlarken sorulacak sorular

MDN'in kurallarını ve uyarılarını bir araya getirdiğimizde, yeni bir veri özniteliği eklemeden önce kendinize sorabileceğiniz kısa bir liste çıkar:

  • Bu bilgiyi kullanıcının görmesi ya da ekran okuyucunun okuması gerekiyor mu? Gerekiyorsa görünür metne yazın.
  • Bu bilgi için zaten bir standart öznitelik ya da öğe var mı? Tarih için <time>, makine okunur ürün kodu için <data>, görsel tembel yükleme için loading gibi.
  • Ad küçük harfli mi, kısa çizgilerden sonra hep harf mi geliyor, xml ile başlamıyor ve iki nokta üst üste içermiyor mu?
  • Değeri JavaScript'te dizge olarak mı kullanacaksınız, yoksa sayıya ya da başka bir türe çevirmeniz mi gerekecek?
  • Değer zamanla değişecek mi? Değişecekse dataset üzerinden yazmanın özniteliği de güncellediğini, yani HTML'in ve CSS seçicilerinin yeni değeri göreceğini hesaba katın.

Son madde önemli bir davranışa işaret eder: dataset bir kopya değildir. MDN, her özelliğin okunabilir ve yazılabilir olduğunu, yazılan değerin özniteliğe yansıdığını gösterir. Bu yüzden durum bilgisini bir veri özniteliğinde tutarsanız, öznitelik seçicisine bağlı stiller de değişikliği izler. MDN'in varyant örneğindeki tek satırlık değişim bunun üzerine kuruludur.

javascript
const kutu = document.querySelector(".bilgi");
kutu.dataset.variant = "uyari";
// Öğe artık data-variant="uyari" özniteliğini taşır

Sık yapılan hatalar

  • Büyük harfli ad kullanıp dataset'te aynısını beklemek: MDN büyük harfli adlardan kaçınmayı önerir; adı baştan küçük harfli ve kısa çizgili yazın, dataset camelCase dönüşümünü kendisi yapar.
  • Kısa çizgiden sonra rakam koymak: data-adim-2 gibi adlar dataset ile okunamaz. data-adim2 ya da data-ikinci-adim tercih edin.
  • Değerin sayı ya da Boolean olacağını sanmak: data-aktif="false" okunduğunda "false" dizgesidir ve JavaScript'te boş olmayan bir dizge olarak ele alınır.
  • Görünür içeriği veri özniteliğine koymak: Ekran okuyucular ve arama motorları bu değerleri görmeyebilir.
  • Uydurma öznitelikler yazmak: <div paket="101"> gibi öneksiz özel öznitelikler yerine data-paket="101" kullanın. Veri öznitelikleri tam olarak bu tür standart dışı hilelere gerek kalmasın diye vardır.
  • Gizli bilgi saklamak: HTML kaynağındaki her öznitelik, sayfayı açan herkes tarafından görülebilir. Veri öznitelikleri gizli değildir, yalnızca görsel olarak gösterilmez.

Sık Sorulan Sorular

data- öznitelikleri HTML doğrulamasından geçer mi?

Evet. data- önekiyle başlayan öznitelikler standartta tanımlı global özniteliklerdir. Adlandırma önerilerine uymasanız bile hata oluşmaz.

getAttribute mı, dataset mi kullanmalıyım?

İkisi aynı değeri döndürür: getAttribute("data-test") ile dataset.test eşdeğerdir. dataset daha kısadır; data-test-1 gibi dataset'in tanımadığı adlar için getAttribute() gerekir.

Bir öğede kaç tane veri özniteliği kullanabilirim?

MDN bir sınır belirtmez; uzay gemisi örneğinde tek bir <img> altı veri özniteliği taşır. Yine de çok sayıda özniteliğe ihtiyaç duyuyorsanız verinin JavaScript tarafında tutulmasının daha uygun olup olmadığını düşünün.

Veri özniteliğindeki değeri CSS ile ekranda göstermek yeterli mi?

CSS'in attr() işleviyle bir veri özniteliğinin değerini oluşturulan içerik olarak gösterebilirsiniz. Ancak MDN, görünür ve erişilebilir olması gereken içeriğin veri özniteliklerinde tutulmamasını, yardımcı teknolojilerin ve arama motorlarının bu değerlere ulaşamayabileceğini hatırlatır. Okuyucunun mutlaka görmesi gereken bir bilgi, HTML'de görünür metin olarak yer almalıdır; CSS ile gösterim yalnızca süsleyici ek bilgiler için düşünülmelidir.

Veri öznitelikleri SVG'de de çalışır mı?

MDN, özel özniteliklerin SVG 2'de de desteklendiğini not eder.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: HTML öğrenme rehberi · Global öznitelikler · time ve data etiketi · JavaScript öğrenme rehberi · template ve slot · schema.org ve JSON-LD