Blog

Vercel’in UI SDK’sını Tailwind ile stillendirmek: data-slot, durum öznitelikleri ve giriş/çıkış animasyonları

Vercel’in yeni UI SDK’sını Tailwind v4 ve shadcn token’larıyla stillendirin: data-slot, durum öznitelikleri, CSS değişkenleri, giriş ve çıkış animasyonları.

Preet Suthar · · 9 dk okuma

  • React
  • UI SDK
  • Tailwind CSS
  • shadcn/ui

Vercel Labs, UI SDK’yı 12 Kasım 2026’da npm’de yayınladı. React, Vue, Svelte, Solid ve Web Components için, davranışlardan oluşan bir çekirdek kütüphane üzerine kurulmuş stilsiz, erişilebilir bileşenler seti. Bileşenler odağı, klavyeyi ve ARIA’yı yönetir. Nasıl göründükleri sizin işiniz.

Bu yazı dördünü Tailwind CSS v4 ve shadcn tarzı tema token’larıyla stillendiriyor: bir Select, bir Popover, bir Rating ve bir Color Picker. Her biri farklı bir stil kancası gösteriyor. Aşağıdaki her kod parçası Vite 8, React 19.3, Tailwind CSS 4.3 ve 0.1.0-beta.1 sürümündeki @ui-sdk/react ile @ui-sdk/core kullanılarak kurulmuş bir deneme uygulamasında çalışıyor. UI SDK beta aşamasında ve dokümanları API’lerin hâlâ değişebileceğini söylüyor, bu yüzden kurduğunuz sürümü kontrol edin.

UI SDK’da stil nasıl çalışır

UI SDK’nın üç katmanı var. @ui-sdk/core, roving focus, typeahead ve açılır öğeler gibi davranışları barındırır. definePrimitive ile yazılan bir primitive, davranışları durum ve adlandırılmış slot’larla birleştirir. @ui-sdk/react gibi bir framework adaptörü her slot’u SelectTrigger ya da RatingItem gibi import ettiğiniz bir parça olarak render eder.

  1. Davranışlar@ui-sdk/coreOdak, tuşlar, seçim, açılır öğeler, sürükle ve bırak.
  2. PrimitivedefinePrimitiveDurum, bir API ve adlandırılmış slot’lar tek bir tanımda.
  3. Parçalar@ui-sdk/reactHer slot data-slot, durum öznitelikleri ve CSS değişkenleriyle render edilir.
  4. Sizin stillerinizclassNameBu kancaları hedefleyen Tailwind yardımcı sınıfları ya da düz CSS.

<div data-slot="select-item" data-highlighted data-selected role="option">

className="data-highlighted:bg-accent data-selected:font-medium"

UI SDK’da stilleriniz nereye bağlanır

Stilleriniz parçalara üç kanca üzerinden bağlanır:

  • data-slot: her parçada bir tane vardır, örneğin data-slot="select-item". Parçayı global CSS ve ajanlar için adlandırır.
  • Durum öznitelikleri: data-open, data-highlighted, data-selected, data-disabled ve benzerleri. Çoğu ya vardır ya yoktur. Bazıları bir değer taşır, örneğin data-side="top" ya da data-orientation="vertical".
  • CSS değişkenleri: bir sınıfın ifade edemediği değerler; örneğin açılır öğedeki --anchor-width ya da yıldızdaki --rating-fill.

className ve style, Base UI’ın izin verdiği gibi parçanın durumunun fonksiyonu da olabilir. Tailwind ile buna nadiren ihtiyaç duyarsınız, çünkü v4’te her data özniteliği için bir varyant vardır: data-highlighted:bg-accent, data-highlighted mevcutken uygulanır.

Dokümanlar, değişebilen üretilmiş ID’ler yerine bu öznitelikleri stillendirmenizi istiyor. Her bileşen sayfasında, her parçanın tam olarak neyi sunduğunu listeleyen bir Styling bölümü ve bir Data Attributes bölümü var. O liste sözleşmedir.

Tailwind v4’ü ve ui-sdk katmanını kurun

UI SDK’nın kendine ait biraz CSS’e ihtiyacı var, örneğin kapalı bir açılır öğeyi gizli tutmak için. Bu CSS’i runtime’da ui-sdk adlı bir cascade katmanında ekler. Sayfa runtime CSS’i nereye eklerse eklesin stilleriniz kazansın diye katmanı global stil dosyanızda, Tailwind import’unun üstünde en başta tanımlayın:

@layer ui-sdk;
@import "tailwindcss";

@custom-variant dark (&:where(.dark, .dark *));

:root {
  --background: oklch(1 0 0);
  --foreground: oklch(0.145 0 0);
  --popover: oklch(1 0 0);
  --primary: oklch(0.205 0 0);
  --primary-foreground: oklch(0.985 0 0);
  --muted: oklch(0.97 0 0);
  --muted-foreground: oklch(0.556 0 0);
  --accent: oklch(0.97 0 0);
  --border: oklch(0.922 0 0);
  --input: oklch(0.922 0 0);
  --ring: oklch(0.708 0 0);
}

@theme inline {
  --color-background: var(--background);
  --color-popover: var(--popover);
  --color-accent: var(--accent);
  --color-muted: var(--muted);
  --color-ring: var(--ring);
}

Token listesinin tamamı, aynı adları geçersiz kılan bir .dark bloğuyla birlikte shadcn/ui’ın ürettiği listedir. Burada kısalttım. UI SDK’daki hiçbir şey bu token’ları okumaz. Yalnızca aşağıdaki sınıflar onları kullandığı için önemlidirler; bu da bir UI SDK bileşeniyle bir shadcn/ui bileşeninin tek bir temayı paylaşabileceği anlamına gelir.

Bağlanacak bir provider ya da paketten import edilecek bir stil dosyası yok. Stiller için 'unsafe-inline' olmadan bir Content Security Policy kullanıyorsanız Styling and Animation kılavuzunun CSP bölümünü okuyun, çünkü runtime CSS bir nonce ya da oluşturulmuş stil sayfaları gerektirir.

Select: durum öznitelikleri ve animasyonlu bir liste

Bir Select’in etiketi, tetikleyicisi, değeri, içerik açılır öğesi ve öğeleri vardır. Bu örnek, seçili öğede onay işareti olan ve liste açılıp kapanırken kısa bir ölçeklenme ve solma animasyonu yapan bir rol seçici gösteriyor:

import {
  Select,
  SelectContent,
  SelectItem,
  SelectItemIndicator,
  SelectLabel,
  SelectTrigger,
  SelectValue,
} from "@ui-sdk/react/select"

const roles = [
  { value: "viewer", label: "Viewer" },
  { value: "editor", label: "Editor" },
  { value: "admin", label: "Admin" },
]

function RoleSelect() {
  return (
    <Select defaultValue="editor" items={roles}>
      <SelectLabel className="text-sm font-medium">Role</SelectLabel>
      <SelectTrigger className="mt-2 flex h-9 w-48 items-center justify-between rounded-md border border-input bg-background px-3 text-sm outline-none focus-visible:ring-3 focus-visible:ring-ring/50 data-open:bg-accent data-placeholder:text-muted-foreground">
        <SelectValue />
      </SelectTrigger>
      <SelectContent
        sideOffset={4}
        className="min-w-(--anchor-width) origin-(--transform-origin) rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-md transition-[opacity,scale] duration-150 ease-out data-starting-style:scale-95 data-starting-style:opacity-0 data-ending-style:scale-95 data-ending-style:opacity-0 motion-reduce:transition-none"
      >
        {roles.map((role) => (
          <SelectItem
            key={role.value}
            value={role.value}
            className="flex h-8 cursor-default items-center justify-between gap-2 rounded-md px-2 text-sm outline-none data-highlighted:bg-accent data-highlighted:text-accent-foreground"
          >
            {role.label}
            <SelectItemIndicator className="text-xs">✓</SelectItemIndicator>
          </SelectItem>
        ))}
      </SelectContent>
    </Select>
  )
}
Tetikleyicisinin altında açık bir Role select; Editor işaretli, Admin vurgulu
Deneme uygulamasında açık Role select. Admin ok tuşlarından gelen data-highlighted’ı taşıyor, Editor ise onay işaretini gösteriyor.

Her sınıfın okuduğu şey:

  • data-open:bg-accent, liste açıkken tetikleyiciyi renkli tutar.
  • data-placeholder: hiçbir şey seçili değilken tetikleyiciyi stillendirir. Varsayılan bir değer olduğu için burada hiç uygulanmaz, ama tutmanın bir maliyeti yok.
  • min-w-(--anchor-width) listeyi en az tetikleyici kadar geniş yapar. Tailwind v4, CSS değişkeni değerini var() olmadan (--name) olarak yazar.
  • origin-(--transform-origin) listeyi açıldığı taraftan ölçekler. UI SDK bu değişkeni içerik üzerinde ayarlar.
  • data-highlighted: işaretçinin ya da klavye odağının altındaki öğeyi işaretler. Seçili öğeler data-selected alır ve SelectItemIndicator yalnızca seçili bir öğenin içinde render edilir.

items geçmek isteğe bağlı, ama dokümanlar bunu öneriyor: tetikleyici liste render edilmeden önce seçili etiketi gösterebilir ve ajan köprüsü liste kapalıyken seçenekleri okuyabilir.

Klavye vurgusunu işaretçi vurgusundan ayırmanız gerekirse, içerikte data-modality="keyboard" ya da "pointer" bulunur. Yalnızca klavye kullanıcılarına görünen bir odak halkası, öğede in-data-[modality=keyboard]:data-highlighted:ring-2 olur.

Açılır öğenin yaşam döngüsü

Yukarıdaki animasyon yalnızca bir geçiş sırasında var olan iki öznitelik kullanır. İçerik ilk karesinde data-starting-style alır, böylece geçişin başlayacağı bir durum olur. Kapanırken data-ending-style alır ve geçiş ya da animasyon bitene kadar sayfada kalır.

  1. KapalıSayfada değil
  2. İlk karedata-opendata-starting-styleAnimasyonun başladığı durumu stillendirin
  3. Açıkdata-openNormal stillerine geçiş yapar
  4. Kapanıyordata-closeddata-ending-styleÇıkış bitene kadar sayfada kalır
  5. Unmount edildiYa da keepMounted ile gizli
Bir UI SDK açılır öğesinin açılıp kapanırken taşıdığı öznitelikler

Bunun pratikte çalışmasını üç ayrıntı sağlıyor.

Birincisi, çıkış stillerini data-closed üzerine değil, data-ending-style üzerine koyun. data-closed durumu tanımlar, ama dokümanlar bunun öğeyi çıkış için sayfada tutmadığını açıkça söylüyor.

İkincisi, UI SDK açılır öğeleri tarayıcının top layer’ını kullanır. İçerik yerinde, bileşenin alt öğesi olarak render edilir ve tarayıcı onu sayfanın üstüne çıkarır. Deneme uygulamamda açık içerik popover="manual" taşıyordu ve :popover-open ile eşleşiyordu. Portal ya da Positioner parçası yoktur ve yapışkan bir başlığın üstünde durup durmayacağına z-index karar vermez.

Üçüncüsü, Motion gibi bir animasyon kütüphanesi kapalı içeriğin DOM’da kalmasını istiyorsa keepMounted ayarlayın. onOpenChangeComplete, açılma ya da kapanma animasyonu dahil bittikten sonra çalışır.

Popover: girişten daha hızlı bir çıkış

Giriş ve çıkışın aynı zamanlamaya ihtiyacı yok. 200ms’de kayarak giren ve 100ms’de solarak çıkan bir popover, iki yönde de 200ms süren birinden daha hızlı hissettirir. Çıkışın kendi özniteliği olduğu için Tailwind ona kendi süresini verebilir:

import {
  Popover,
  PopoverClose,
  PopoverContent,
  PopoverDescription,
  PopoverTitle,
  PopoverTrigger,
} from "@ui-sdk/react/popover"

function ShareProject() {
  return (
    <Popover>
      <PopoverTrigger className="h-9 rounded-md border border-input bg-background px-3 text-sm font-medium outline-none hover:bg-accent focus-visible:ring-3 focus-visible:ring-ring/50 data-open:bg-accent">
        Share
      </PopoverTrigger>
      <PopoverContent
        side="bottom"
        align="start"
        sideOffset={8}
        className="w-72 origin-(--transform-origin) rounded-lg border border-border bg-popover p-4 text-popover-foreground shadow-md transition-[opacity,scale,translate] duration-200 ease-out data-starting-style:-translate-y-1 data-starting-style:scale-95 data-starting-style:opacity-0 data-ending-style:scale-95 data-ending-style:opacity-0 data-ending-style:duration-100 motion-reduce:transition-none"
      >
        <PopoverTitle className="text-sm font-medium">
          Share project
        </PopoverTitle>
        <PopoverDescription className="mt-1 text-sm text-muted-foreground">
          Anyone with the link can view Atlas.
        </PopoverDescription>
        <PopoverClose className="mt-3 h-8 rounded-md bg-primary px-3 text-sm font-medium text-primary-foreground">
          Copy link
        </PopoverClose>
      </PopoverContent>
    </Popover>
  )
}
Başlık, açıklama ve Copy link düğmesi olan açık bir Share popover’ı
Girişinden sonra Share popover’ı. Ölçeklenip solarak belirirken 4px aşağı kayar.

Giriş -translate-y-1, scale-95 ve opacity-0 değerlerinden durağan duruma geçer. Çıkış yalnızca data-ending-style:duration-100 ile ölçeklenir ve solar. motion-reduce:transition-none daha az hareket isteyenler için ikisini de kapatır; popover yine açılıp kapanır.

PopoverTitle ve PopoverDescription görünümün ötesinde önemlidir. İçerik bir dialog’dur ve bu parçalar ona erişilebilir bir ad ve açıklama verir. Başlık yoksa içeriğe bir aria-label verin.

Rating: yıldızları değil, dolguyu stillendirin

Rating, yıldız olarak çizilmiş bir radio grubudur. Tek bir RatingItem render edersiniz, Rating onu her yıldız için tekrarlar. Her öğe, gösterilen puanın kendi yıldızının ne kadarını kapladığını 0 ile 1 arasında --rating-fill ile bildirir. data-filled tam yıldızları, data-partial yarım puanın bittiği yıldızı, data-highlighted ise işaretçinin önizlediği puana kadarki yıldızları işaretler.

--rating-fill sayesinde yarım yıldızlar iki ikon yerine tek bir gradyandan çıkar:

import { Rating, RatingItem } from "@ui-sdk/react/rating"

const star =
  "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2l3.1 6.3 6.9 1-5 4.9 1.2 6.8L12 17.8 5.8 21l1.2-6.8-5-4.9 6.9-1z'/%3E%3C/svg%3E\")"

function StayRating() {
  return (
    <Rating
      aria-label="How was your stay?"
      step={0.5}
      defaultValue={3.5}
      className="inline-flex gap-1"
    >
      <RatingItem className="size-7 rounded-sm [&_button]:outline-none has-focus-visible:outline-2 has-focus-visible:outline-offset-2 has-focus-visible:outline-ring">
        <span
          aria-hidden="true"
          style={{ maskImage: star, WebkitMaskImage: star }}
          className="absolute inset-0 bg-[linear-gradient(to_right,var(--color-amber-400)_calc(var(--rating-fill)*100%),var(--color-muted)_0)] in-data-highlighted:bg-[linear-gradient(to_right,var(--color-amber-300)_calc(var(--rating-fill)*100%),var(--color-muted)_0)]"
        />
      </RatingItem>
    </Rating>
  )
}
İşaretçi bir puanı önizlerken dört buçuğu daha açık bir kehribar renkle dolmuş beş yıldız
İşaretçi beşinci yıldızın ilk yarısında duruyor. Dolgu --rating-fill’i izliyor, daha açık kehribar renk ise data-highlighted’dan geliyor.

step={0.5} ile her yarım yıldız, "3.5 stars" gibi adlandırılmış kendi radio’sudur. Radio’lar, Rating’in ikonunuzun üzerine satır içi stillerle yerleştirdiği düğmelerdir; öğe de aynı şekilde position: relative alır. Bu yüzden span ek bir sınıf olmadan absolute inset-0 kullanabilir.

Klavye, sizin hiçbir şey yapmanıza gerek kalmadan çalışır. Testimde işaretli yıldıza odaklanıp sağ ok tuşuna basınca puan 3.5’ten 4’e çıktı ve dolgu da onu izledi.

Maskeyi odaklanabilir öğeden uzak tutun

İlk sürümüm yıldız maskesini doğrudan RatingItem üzerine koyuyordu. Tab ile girene kadar doğru görünüyordu: CSS maskesi, çerçeveler dahil öğenin çizdiği her şeyi kırpar, bu yüzden odak halkası kayboldu. Maskeyi içteki bir span’e taşımak sorunu çözdü. Öğe yuvarlak çerçevesini has-focus-visible: ile korur, [&_button]:outline-none ise içerideki yarım genişlikteki radio düğmesinde tarayıcının varsayılan halkasını gizler; yoksa bu halka yarım yıldızın etrafına ince bir kutu çizer.

Dördüncü yıldızda klavye odağı olan iki sıra yıldız. Solda odak halkası görünmüyor. Sağda yıldızın etrafında yuvarlak bir halka var
Aynı klavye odağı, iki yapı. Solda: maske RatingItem üzerinde ve çerçeveyi kırpıyor. Sağda: maske içteki bir span üzerinde ve halka görünüyor.

Bu UI SDK’ya özgü değil, ama ikon biçimli maskeler puanlamaları çizmenin yaygın bir yoludur; bu yüzden yayınlamadan önce klavyeyle kontrol etmeye değer.

Color Picker: çizimi CSS değişkenleri yapar

Color Picker, dördü arasında en çok değişkeni sunan bileşen. Her parça geçerli rengi --color-picker-color olarak yazar. Alan, iki kanalı için bir dizi gradyan olan --color-area-background değerini alır, her kaydırıcı da --color-slider-background değerini. Sınıflarınız parçalara bir boyut verir ve bu değişkenleri arka plan olarak kullanır.

import {
  ColorPicker,
  ColorPickerArea,
  ColorPickerAreaThumb,
  ColorPickerInput,
  ColorPickerSlider,
  ColorPickerSliderThumb,
  ColorPickerSwatch,
} from "@ui-sdk/react/color-picker"
import { Popover, PopoverContent, PopoverTrigger } from "@ui-sdk/react/popover"

const thumb =
  "absolute size-4 -translate-1/2 rounded-full border-2 border-white bg-(--color-picker-color) shadow outline-none ring-1 ring-black/20 focus-visible:ring-3 focus-visible:ring-ring"

function BrandColor() {
  return (
    <ColorPicker aria-label="Brand color" defaultValue="#6366f1">
      <Popover>
        <PopoverTrigger
          aria-label="Brand color"
          className="flex h-9 items-center gap-2 rounded-md border border-input bg-background pr-3 pl-1.5 text-sm outline-none focus-visible:ring-3 focus-visible:ring-ring/50"
        >
          <ColorPickerSwatch className="size-6 rounded-sm bg-(--color-picker-color) ring-1 ring-black/10 ring-inset" />
          Brand color
        </PopoverTrigger>
        <PopoverContent
          sideOffset={8}
          className="flex w-60 origin-(--transform-origin) flex-col gap-3 rounded-lg border border-border bg-popover p-3 shadow-md transition-[opacity,scale] duration-150 ease-out data-starting-style:scale-95 data-starting-style:opacity-0 data-ending-style:scale-95 data-ending-style:opacity-0 motion-reduce:transition-none"
        >
          <ColorPickerArea className="relative h-36 rounded-md bg-(image:--color-area-background)">
            <ColorPickerAreaThumb className={thumb} />
          </ColorPickerArea>
          <ColorPickerSlider
            channel="hue"
            className="relative h-3 rounded-full bg-(image:--color-slider-background)"
          >
            <ColorPickerSliderThumb className={`${thumb} top-1/2`} />
          </ColorPickerSlider>
          <ColorPickerInput
            aria-label="Hex"
            className="h-8 rounded-md border border-input bg-background px-2 font-mono text-sm outline-none focus-visible:ring-3 focus-visible:ring-ring/50"
          />
        </PopoverContent>
      </Popover>
    </ColorPicker>
  )
}
Çivit mavisi renk örneği olan bir Brand color düğmesi ve altında doygunluk alanı, ton kaydırıcısı ve #6366f1 gösteren hex girişiyle açık bir seçici
Bir Popover içindeki seçici. Renk örneği, iki tutamaç ve alan, tamamı UI SDK’nın CSS değişkenleriyle boyanıyor.

Bunu kopyalamadan önce bilmeye değer şeyler:

  • Popover, ColorPicker’ın içine girer. Böylece açılır öğedeki parçalar ve tetikleyicideki renk örneği aynı rengi düzenler ve gösterir.
  • bg-(image:--color-area-background), Tailwind v4’ün tür ipucudur. image: olmadan Tailwind değişkeni bir renk olarak okur ve gradyanlar boyanmaz.
  • Tutamaçlar position: absolute ve yüzde cinsinden konumlarını satır içi stil olarak alır. Sınıfınızın yalnızca her tutamacı kendi noktasında ortalaması gerekir; -translate-1/2 bunu yapar. Kaydırıcı tutamacı ayrıca top-1/2 ister, çünkü satır içi stili yalnızca iz boyunca konumu ayarlar.
  • Renk örneği ekran okuyucular için, rengin adını taşıyan bir görseldir. Benim yapımda #6366f1 için "vivid purple" olarak okundu. Tetikleyiciyi kendiniz adlandırın, çünkü görünen metin tek başına rengin ne için olduğunu söylemeyebilir.
  • OKLCH için alanın içine ColorPickerAreaCanvas ekleyin. Bir gradyan OKLCH’nin gamut sınırını çizemez, bu yüzden canvas onu piksel piksel boyar.

Düz CSS’te data-slot ile stil vermek

Her parçaya yardımcı sınıflar vermek bir seçenek. Diğeri data-slot’a göre yazılmış bir stil dosyası; bu, markup’ı kısa tutar ve bir bileşenin görünümünü tek bir yerde toplar:

[data-slot="select-item"] {
  display: flex;
  height: 2rem;
  align-items: center;
  border-radius: calc(var(--radius) - 2px);
  padding-inline: 0.5rem;
}

[data-slot="select-item"][data-highlighted] {
  background: var(--accent);
  color: var(--accent-foreground);
}

[data-slot="select-content"][data-starting-style],
[data-slot="select-content"][data-ending-style] {
  opacity: 0;
  scale: 0.95;
}

UI SDK dokümanları kendi demolarını da düz CSS ile stillendiriyor. Bu işe yarıyor çünkü data-slot, bir parçanın her zaman koruduğu özniteliklerden biri: dokümanlar onu rollerin ve tabindex’in yanında, prop’larınızın geçersiz kılamayacağı yönetilen öznitelikler arasında listeliyor. Her bileşen dosyasının parçaları sarıp kendi sınıflarını eklediği shadcn/ui tarzı bir projede parçalardaki yardımcı sınıflar genellikle daha basittir. Düz CSS teması ise toptan değiştirmeye daha uygundur.

shadcn tarzı sınıfları Radix’ten ya da Base UI’dan taşımak

Bileşenleriniz shadcn/ui’dan geliyorsa sınıflarınızın çoğu aynen taşınır. Farklar birkaç öznitelik adında ve açılır öğe yapısındadır.

KonuRadixBase UIUI SDK
Açık durumdata-[state=open]:data-open:data-open:
Giriş stilleridata-[state=open] üzerinde keyframe’lerdata-starting-style:data-starting-style:
Çıkış stilleridata-[state=closed] üzerinde keyframe’lerdata-ending-style:data-ending-style:
Dönüşüm orijini--radix-popover-content-transform-origin--transform-origin--transform-origin
Tetikleyici genişliği--radix-popover-trigger-width--anchor-width--anchor-width
Açılır öğe parçalarıPortal, ContentPortal, Positioner, PopupYalnızca Content

Base UI’dan geliyorsanız açılır öğelerin öznitelik adları aynıdır, bu yüzden sınıf string’leri çoğunlukla olduğu gibi taşınır. Portal ve Positioner sarmalayıcılarını silip side, align ve sideOffset gibi konumlandırma prop’larını içeriğe taşırsınız. Radix’ten geliyorsanız data-[state=…] varyantlarını ve keyframe animasyonlarını başlangıç ve bitiş öznitelikleriyle değiştirirsiniz. Her iki durumda da her bileşenin Data Attributes listesini kontrol edin, çünkü ortak görünen adlar farklı olabilir. Örneğin Base UI’ın Select’inin kendi öznitelik seti vardır, UI SDK’nınkinin de.

Üç kütüphanenin stilin ötesinde bütün olarak karşılaştırması UI SDK, Base UI ve Radix yazısında.

Beni zorlayanlar

Tekrarlamamanız için kısa bir liste:

  • Çıkış için data-closed stillendirmek. Hiçbir şey animasyonlanmaz. data-ending-style kullanın.
  • @layer ui-sdk; satırını unutmak. En başta olmazsa runtime CSS, cascade’de stillerinizden sonra gelebilir.
  • Odaklanabilir parçalarda maskeler. Odak çerçevesini kırparlar. İçteki bir öğeyi maskeleyin.
  • --available-height değerini bir alt öğeden okumak. Dokümanlar bunun miras alınmadığını belirtiyor. Değeri açılır öğede kopyalayın, örneğin [--list-height:var(--available-height)], ve aşağıda max-h-(--list-height) ile okuyun.
  • Değişkenlerden gradyanlar. bg-(--name) değil, bg-(image:--name) kullanın.

UI SDK bir beta ve bu yazı yazılırken bir günlük. Buradaki her şey 0.1.0-beta.1’de dokümante edildiği gibi çalıştı ve node_modules/@ui-sdk/react/docs/ altındaki paketle gelen dokümanlardaki öznitelik listeleri, bileşenlerin render ettikleriyle eşleşiyor. HextaUI, bileşenlerinin Base UI sürümünden ayrı, stillendirilmiş bir UI SDK sürümü üzerinde çalışıyor; bu yazı da ilk parçaları yaparken öğrendiklerim.