Tailwind CSS'te bir öğeyi ebeveyninin durumuna göre biçimlendirmek için ebeveyne group sınıfını verir, çocukta group-hover:, group-focus: gibi varyantlar kullanırsınız. Bir öğeyi kendinden önce gelen kardeşinin durumuna göre biçimlendirmek için ise o kardeşe peer sınıfını verir, hedefte peer-checked:, peer-invalid:, peer-focus: yazarsınız. Öğenin kendi alt öğelerine bakan has-* ve group sınıfı gerektirmeyen in-* varyantları da aynı ailenin parçasıdır.

Bu yazıda her birinin ürettiği seçiciyi, adlandırılmış grup ve peer'ları (group/ad, peer/ad), keyfi seçicili kullanımları, JavaScript'siz bir hata mesajı ve kayan etiket örneğini, son olarak has-checked ile seçilebilir kartları v4.3.5 ile derlenmiş gerçek çıktılarla inceliyoruz. Öğenin kendi durumuna bakan hover:, focus: gibi varyantlar hover, focus ve active durumları yazısında; serinin tamamı Tailwind öğrenme rehberinde.

group: ebeveynin durumuna göre çocuğu biçimlendirmek

group: ebeveynin durumuna göre çocuğu biçimlendirmek

Resmî durum sayfasındaki tarife göre ebeveyni group ile işaretler, hedef öğede group-* varyantlarını kullanırsınız. Aşağıdaki örnekte bütün kart bir bağlantıdır; karta gelindiğinde hem arka plan hem de içindeki iki metnin rengi değişir.

html
<a href="#" class="group block rounded-lg p-4 hover:bg-sky-50">
  <h3 class="font-semibold group-hover:text-sky-700">Yazı başlığı</h3>
  <p class="text-gray-500 group-hover:text-gray-900">Kısa özet</p>
</a>

v4.3.5 ile derlenen CSS:

css
/* (kısaltıldı) */
@layer utilities {
  .block {
    display: block;
  }
  .rounded-lg {
    border-radius: var(--radius-lg);
  }
  .p-4 {
    padding: calc(var(--spacing) * 4);
  }
  .font-semibold {
    --tw-font-weight: var(--font-weight-semibold);
    font-weight: var(--font-weight-semibold);
  }
  .text-gray-500 {
    color: var(--color-gray-500);
  }
  @media (hover: hover) {
    :is(:where(.group):hover .group-hover\:text-gray-900) {
      color: var(--color-gray-900);
    }
    :is(:where(.group):hover .group-hover\:text-sky-700) {
      color: var(--color-sky-700);
    }
    .hover\:bg-sky-50:hover {
      background-color: var(--color-sky-50);
    }
  }
}

Çıktıda üç önemli ayrıntı var. Birincisi, group sınıfının kendisi hiçbir CSS kuralı üretmez; yalnızca seçicilerde bir işaret olarak kullanılır. İkincisi, seçici :is(:where(.group):hover .group-hover\:text-sky-700) biçimindedir: ".group sınıflı ve üzerine gelinmiş bir atanın içindeki hedef öğe". .group kısmı :where() ile sarıldığı için seçiciliğe katkı yapmaz; kuralın ağırlığı, öğenin kendi hover: sınıfıyla aynı kalır ve sıralama mantığı bozulmaz. Üçüncüsü, group-hover da hover gibi @media (hover: hover) içinde üretildi; dokunmatik birincil girişli aygıtlarda bu kurallar uygulanmaz.

Resmî sayfaya göre bu kalıp her sözde sınıf varyantıyla çalışır: group-focus, group-active, hatta group-odd. Derlemede group-focus:underline için :is(:where(.group):focus .group-focus\:underline), group-odd:p-1 için :is(:where(.group):nth-child(odd) .group-odd\:p-1) seçicisi oluştu. Kırılma noktalarıyla yığmak da mümkündür: group-hover:md:p-2 hover sorgusunun içinde bir @media (width >= 48rem) bloğu üretti.

Adlandırılmış gruplar: iç içe gruplarda doğru atayı seçmek

Bir grup başka bir grubun içindeyse, adsız group-hover herhangi bir .group atasına gelindiğinde eşleşir. Belirli bir atayı hedeflemek için resmî sayfa ataya group/{ad}, hedefe group-hover/{ad} yazmayı gösterir. Adlar için yapılandırma gerekmez.

html
<ul>
  <li class="group/satir flex">
    <a class="group/link">Ad Soyad</a>
    <span class="invisible group-hover/satir:visible">Düzenle</span>
    <span class="group-hover/link:underline">Profil</span>
  </li>
</ul>

v4.3.5 ile derlenen CSS:

css
/* (kısaltıldı) */
@layer utilities {
  .invisible {
    visibility: hidden;
  }
  .flex {
    display: flex;
  }
  @media (hover: hover) {
    :is(:where(.group\/link):hover .group-hover\/link\:underline) {
      text-decoration-line: underline;
    }
    :is(:where(.group\/satir):hover .group-hover\/satir\:visible) {
      visibility: visible;
    }
  }
}

Ad, sınıf adının bir parçası olarak seçiciye girer: .group\/satir. "Düzenle" yazısı yalnızca satıra gelindiğinde görünür olur. Bu örnekte bir hata da saklı: "Profil" yazısı group/link sınıflı bağlantının içinde değil, onun kardeşidir. Seçici bir soy ilişkisi (boşluk) aradığı için bağlantıya gelinmesi "Profil" yazısını etkilemez. Grup her zaman hedefin bir atası olmalıdır; kardeş ilişkisi için peer kullanılır.

Keyfi gruplar ve in-* varyantı

Hazır bir sözde sınıf yetmediğinde köşeli parantezle kendi seçicinizi yazabilirsiniz. Resmî sayfadaki örnekler group-[.is-published]:block ve & işaretiyle grubun yerini belirten group-[:nth-of-type(3)_&]:block sınıflarıdır. Alt çizgi boşluk anlamına gelir.

css
/* (kısaltıldı) */
@layer utilities {
  :is(:where(.group):is(.is-published) .group-\[\.is-published\]\:block) {
    display: block;
  }
  :is(:nth-of-type(3) :where(.group) .group-\[\:nth-of-type\(3\)_\&\]\:block) {
    display: block;
  }
  :where(:focus) .in-focus\:opacity-100 {
    opacity: 100%;
  }
}

Yukarıdaki çıktı @source inline("group-[.is-published]:block group-[:nth-of-type(3)_&]:block in-focus:opacity-100") girdisinin v4.3.5 ile derlenmiş utilities katmanıdır. İlk kural "is-published sınıfı da olan bir grubun içi" demektir. İkincisinde & grubun yerini aldı: "üçüncü nth-of-type öğenin içindeki bir grubun içi". Son kural in-* varyantıdır: resmî sayfaya göre group gibi çalışır ama ebeveyne group eklemeniz gerekmez. Bedeli de seçicide görülür: :where(:focus) herhangi bir odaklı ataya yanıt verir. Sayfa daha ince kontrol için group kullanılmasını önerir.

in-* de köşeli parantez kabul eder: in-[.acik]:p-2 derlendiğinde :where(:is(.acik)) .in-\[\.acik\]\:p-2 seçicisini üretti, yani acik sınıflı herhangi bir atanın içindeki öğeye iç boşluk verir. Bir akordeon ya da menü açıldığında JavaScript'in yalnızca ataya bir sınıf eklemesi, içerideki bütün öğelerin buna göre biçimlenmesi için yeterlidir.

Uygulamalı örnek: fareyle ve klavyeyle açılan satır işlemleri

Uygulamalı örnek: fareyle ve klavyeyle açılan satır işlemleri

Tablo veya liste satırlarında "Düzenle" ve "Sil" gibi işlemleri yalnızca satıra gelindiğinde göstermek yaygın bir kalıptır. Yalnızca group-hover:visible kullanırsanız, klavyeyle dolaşan kullanıcı satırdaki düğmeye Tab ile geldiğinde düğme görünmez kalır; dokunmatik birincil girişli aygıtta da hiç görünmez. Çözüm, aynı öğeye bir de group-focus-within:visible eklemektir.

html
<li class="group flex justify-between">
  <span>Fatura 2026-11</span>
  <button class="invisible group-hover:visible group-focus-within:visible">Düzenle</button>
</li>

v4.3.5 ile derlenen CSS:

css
/* (kısaltıldı) */
@layer utilities {
  .invisible {
    visibility: hidden;
  }
  .flex {
    display: flex;
  }
  .justify-between {
    justify-content: space-between;
  }
  :is(:where(.group):focus-within .group-focus-within\:visible) {
    visibility: visible;
  }
  @media (hover: hover) {
    :is(:where(.group):hover .group-hover\:visible) {
      visibility: visible;
    }
  }
}

:focus-within satırın içindeki herhangi bir öğe odaktayken eşleştiği için, Tab ile düğmeye gelindiği anda düğme görünür olur. Bu sayede gizli işlemler klavye kullanıcıları için de erişilebilir kalır. Dokunmatik aygıtlar için en güvenli yol ise işlemleri her zaman görünür bırakmak ya da yalnızca geniş ekranlarda gizlemektir. Erişilebilirlik varyantlarının geri kalanı erişilebilirlik: sr-only ve focus-visible yazısında.

peer: önceki kardeşin durumuna göre biçimlendirmek

Bir form alanının yanındaki mesaj veya etiket gibi, ebeveyn değil kardeş ilişkisi olan durumlarda peer kullanılır. Resmî sayfadaki örnekte e-posta alanı geçersizken altındaki uyarı görünür hâle gelir.

html
<label>
  <input type="email" class="peer border" placeholder="E-posta">
  <p class="invisible text-red-600 peer-invalid:visible">Geçerli bir e-posta adresi girin.</p>
</label>

v4.3.5 ile derlenen CSS:

css
/* (kısaltıldı) */
@layer utilities {
  .invisible {
    visibility: hidden;
  }
  .border {
    border-style: var(--tw-border-style);
    border-width: 1px;
  }
  .text-red-600 {
    color: var(--color-red-600);
  }
  :is(:where(.peer):invalid ~ .peer-invalid\:visible) {
    visibility: visible;
  }
}

Seçicideki ~ işareti CSS'in sonraki kardeş birleştiricisidir: ".peer sınıflı ve geçersiz bir öğeden sonra gelen kardeş". Uyarı varsayılan olarak invisible ile gizlidir; alan geçersizken visible olur. invisible kullanılmasının nedeni, gizliyken de yer kaplayıp sayfanın kaymasını önlemesidir; hidden ise öğeyi düzenden tamamen çıkarır. Görünürlük sınıfları display ve hidden yazısında.

Burada dikkat edilmesi gereken bir nokta: invalid varyantı yalnızca :invalid sözde sınıfına bakar, kullanıcının alanla etkileşip etkileşmediğini dikkate almaz. Resmî sayfaya göre user-valid ve user-invalid ise yalnızca kullanıcı etkileşiminden sonra uygulanır. Uyarının, kullanıcı alanla daha hiç ilgilenmeden görünmesini istemiyorsanız peer-user-invalid:visible yazabilirsiniz; derlendiğinde :is(:where(.peer):user-invalid ~ .peer-user-invalid\:visible) seçicisini üretti. Form durumlarının tamamı form durumları yazısında.

Uygulamalı örnek: JavaScript'siz kayan etiket

Resmî sayfa peer ile kayan etiket (floating label) gibi şeylerin JavaScript olmadan yapılabileceğini belirtir. Aşağıdaki örnekte etiket, alan boşken içeride büyük, odakta veya doluyken yukarıda küçük durur. Hile, input'a tek bir boşluktan oluşan bir placeholder verip placeholder-shown durumunu "alan boş" anlamında kullanmaktır.

html
<div class="relative">
  <input id="ad" placeholder=" " class="peer w-full border px-3 pt-5 pb-2">
  <label for="ad" class="absolute top-1 left-3 text-xs text-gray-500 peer-placeholder-shown:top-3.5 peer-placeholder-shown:text-base peer-focus:top-1 peer-focus:text-xs peer-focus:text-sky-600">Adınız</label>
</div>

v4.3.5 ile derlenen CSS (konu dışı genel sınıflar çıkarıldı):

css
@layer utilities {
  /* (kısaltıldı) */
  .top-1 {
    top: var(--spacing);
  }
  .text-xs {
    font-size: var(--text-xs);
    line-height: var(--tw-leading, var(--text-xs--line-height));
  }
  :is(:where(.peer):placeholder-shown ~ .peer-placeholder-shown\:top-3\.5) {
    top: calc(var(--spacing) * 3.5);
  }
  :is(:where(.peer):placeholder-shown ~ .peer-placeholder-shown\:text-base) {
    font-size: var(--text-base);
    line-height: var(--tw-leading, var(--text-base--line-height));
  }
  :is(:where(.peer):focus ~ .peer-focus\:top-1) {
    top: var(--spacing);
  }
  :is(:where(.peer):focus ~ .peer-focus\:text-xs) {
    font-size: var(--text-xs);
    line-height: var(--tw-leading, var(--text-xs--line-height));
  }
  :is(:where(.peer):focus ~ .peer-focus\:text-sky-600) {
    color: var(--color-sky-600);
  }
}

Sıralama burada işi çözer. Alan boşken placeholder görünür sayılır ve etiket 0.875rem yukarıda (top-3.5), 1rem boyutunda durur. Alan odaklanınca hem placeholder-shown hem focus kuralları doğrudur; derlenen dosyada focus kuralları sonra geldiği için etiket yukarı çıkar ve küçülür. Kullanıcı bir şey yazınca placeholder kaybolur, yalnızca öneksiz top-1 text-xs kalır ve etiket yukarıda kalır. Burada --text-xs 0.75rem, --text-base 1rem'dir. Konumlandırma sınıfları position, absolute ve inset yazısında.

Adlandırılmış ve keyfi peer'lar

Birden çok peer'ın bulunduğu formlarda belirli bir kardeşi hedeflemek için gruplardaki gibi ad verilir: peer/draft ve peer-checked/draft:text-sky-500. Keyfi seçici de mümkündür: resmî örnek peer-[.is-dirty]:peer-required:block. Derlenen seçiciler şunlardır:

css
/* (kısaltıldı) */
@layer utilities {
  :is(:where(.peer\/draft):checked ~ .peer-checked\/draft\:text-sky-500) {
    color: var(--color-sky-500);
  }
  :is(:where(.peer):required ~ :is(:where(.peer):is(.is-dirty) ~ .peer-\[\.is-dirty\]\:peer-required\:block)) {
    display: block;
  }
}

İkinci kural iki peer koşulunu iç içe yığar: hedef, is-dirty sınıflı bir peer'dan sonra gelmeli ve o yapının tamamı da required bir peer'dan sonra yer almalıdır. Bu tür uzun seçiciler güçlüdür ama okunması zordur; çoğu formda adlandırılmış peer yeterli olur.

has-*: alt öğelere göre biçimlendirmek

has-* varyantı ilişkiyi tersine çevirir: öğe, kendi içindeki bir öğenin durumuna veya varlığına göre biçimlenir. Resmî sayfadaki ödeme yöntemi örneğinde seçilen radyo düğmesini içeren etiket vurgulanır.

html
<label class="flex gap-2 rounded-lg border p-4 has-checked:border-indigo-500 has-checked:bg-indigo-50">
  <input type="radio" name="odeme" class="accent-indigo-600">
  Kredi kartı
</label>

v4.3.5 ile derlenen CSS (has kuralları):

css
@layer utilities {
  /* (kısaltıldı) */
  .accent-indigo-600 {
    accent-color: var(--color-indigo-600);
  }
  .has-checked\:border-indigo-500:has(:checked) {
    border-color: var(--color-indigo-500);
  }
  .has-checked\:bg-indigo-50:has(:checked) {
    background-color: var(--color-indigo-50);
  }
}

:has(:checked) seçicisi sayesinde etiket, içindeki radyo seçildiği anda kenarlık ve arka plan rengini değiştirir; ayrıca peer ya da JavaScript gerekmez, radyonun etiketin neresinde durduğu da önemli değildir. Köşeli parantezle içerik de sorgulanabilir: has-[img]:p-4 :has(:is(img)) üretti. Gruplar ve peer'larla birleşik biçimler de vardır: group-has-[a]:block grubun içinde bir bağlantı varsa, peer-has-checked:hidden peer'ın içinde seçili bir öğe varsa çalışır. not-has-checked:opacity-50 ise :not(:has(:checked)) ile tersini yapar.

Hangisini ne zaman kullanmalı?

Hangisini ne zaman kullanmalı? group-*, in-*, peer-*, has-*
VaryantBaktığı yerÜrettiği seçici biçimiTipik kullanım
group-*group sınıflı ata:where(.group):hover hedefKartın tamamına gelince içerik değişsin
in-*Herhangi bir ata:where(:focus) hedefİşaret eklemeden basit ata durumu
peer-*Önceki kardeş:where(.peer):checked ~ hedefForm alanının yanındaki mesaj veya etiket
has-*Kendi alt öğelerihedef:has(:checked)Seçili radyoyu içeren kartı vurgulamak
group-has-*Atanın alt öğeleri:where(.group):has(...) hedefGrupta resim varsa başlığı göster

Tablodaki seçicilerin ortak noktası, işaret sınıflarının (.group, .peer) ve in-* koşulunun hep :where() içinde durmasıdır. İşaret sınıfı seçiciliğe katkı yapmaz; kuralın ağırlığı hedef sınıftan ve dışarıda kalan sözde sınıftan (:hover, :checked gibi) gelir. Sonuçta group-hover: ya da peer-checked: ile yazılan bir kural, öğenin kendi hover: veya checked: varyantıyla aynı ağırlıktadır ve ad verdiğinizde ya da grupları iç içe koyduğunuzda ağırlık artmaz. Aynı ağırlıktaki kurallar arasında derlenen dosyadaki sıra belirleyicidir.

Sık yapılan hatalar

  • group sınıfını unutmak: group-hover: kuralları üretilir ama .group sınıflı bir ata yoksa eşleşmez.
  • peer'ı hedeften sonra yazmak: ~ birleştiricisi geriye bakmaz; peer önce gelmelidir.
  • Kardeş için group kullanmak: group bir soy ilişkisi arar. Kardeşler arasında peer kullanın.
  • İç içe gruplarda ad vermemek: Adsız group-hover en yakın değil, herhangi bir .group atasına yanıt verir.
  • Boş alanda hemen hata göstermek: peer-invalid kullanıcı etkileşimini beklemez; peer-user-invalid yalnızca etkileşimden sonra uygulanır.
  • Hover'a dayalı gizli işlevler: group-hover:visible ile açılan düğmeler dokunmatik birincil girişli aygıtlarda görünmez. Aynı içeriğe group-focus-within:visible gibi bir yol da ekleyin.

Sık Sorulan Sorular

group ve peer için yapılandırma gerekir mi?

Hayır. Resmî sayfaya göre adlandırılmış gruplar ve peer'lar da dahil hepsi yalnızca işaretlemede kullanılarak çalışır; derleyici gerekli CSS'i kaynakta gördüğü sınıflardan üretir.

peer ile has-* arasında nasıl seçim yaparım?

Hedef, durumu değişen öğeden sonra gelen bir kardeşse peer; hedef, durumu değişen öğeyi içeren bir ataysa has-* kullanılır. Radyo düğmeli kartlarda has-* genellikle daha sadedir.

has-* ile group-has-* arasındaki fark nedir?

has-checked:bg-indigo-50 stili, içinde seçili öğe bulunan öğenin kendisine verir. group-has-[img]:opacity-100 ise stili, içinde resim bulunan .group atasının herhangi bir alt öğesine verir; derlendiğinde :is(:where(.group):has(:is(img)) .group-has-\[img\]\:opacity-100) üretti. Yani biri durumu taşıyan kabı, diğeri o kabın içindeki başka bir öğeyi biçimlendirir.

group-hover neden mobilde çalışmıyor?

Derlemede group-hover kuralları da @media (hover: hover) içinde üretilir. Bu davranışın nedeni ve alternatifleri hover, focus ve active yazısında.

Keyfi varyantlar başka nerede kullanılır?

[&_p]:mt-4 gibi tamamen keyfi seçiciler ve @custom-variant ile kendi varyantınızı tanımlamak @custom-variant ve keyfi varyantlar yazısında anlatılıyor.

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: Tailwind öğrenme rehberi · hover ve focus · Form durumları · Keyfi varyantlar · Kart ve buton örnekleri · display ve hidden