shadcn/ui'da açılır liste için iki bileşen vardır. Select, Radix UI'ın Select ilkeli üzerine kurulu, bir butonla açılan ve tamamen stillendirilmiş bir seçenek listesidir. NativeSelect ise tarayıcının kendi select öğesini tasarım sisteminize uyan sınıflarla sarar. Belgelerin önerisi kısadır: tarayıcının yerel davranışına, daha iyi performansa ya da mobil cihazlara uygun açılır listeye ihtiyacınız varsa NativeSelect, özel stil, animasyon ya da karmaşık etkileşim istiyorsanız Select kullanın.
Bu yazıda iki bileşeni de belge sayfaları ve kaynak kodla ayrıntılı inceliyoruz: Select'in parçaları, gruplar ve ayırıcılar, uzun listelerde kaydırma, kontrollü kullanım, tetikleyici boyutu, position seçeneği ve form entegrasyonu; ardından NativeSelect'in gruplu, devre dışı ve hatalı durumları ile erişilebilirlik notları. İçinde arama yapılabilen bir liste gerekiyorsa o iş Select'in değil Combobox bileşeninin konusu. Serinin tamamı shadcn/ui öğrenme rehberi sayfasında.
Select: kurulum ve parçalar

Select, npx shadcn@latest add select komutuyla eklenir; elle kurulumda @radix-ui/react-select paketi gerekir. Belge sayfasındaki tanım, kullanıcının seçim yapacağı bir seçenek listesinin bir butonla açılmasıdır. Kaynak dosya Radix'in parçalarını birer birer sarar:
npx shadcn@latest add select| Parça | Görevi |
|---|---|
| Select | Kök bileşen; seçili değeri ve açık/kapalı durumu yönetir |
| SelectTrigger | Listeyi açan buton; sağında aşağı ok ikonu bulunur, size sm veya default |
| SelectValue | Tetikleyicinin içinde seçili değeri ya da placeholder metnini gösterir |
| SelectContent | Açılan liste; portal içinde render edilir, kaydırma butonlarını kendisi ekler |
| SelectGroup ve SelectLabel | Seçenekleri başlıklı gruplara ayırır |
| SelectItem | Tek bir seçenek; seçiliyse sağında onay işareti görünür |
| SelectSeparator | Gruplar arasına ince bir çizgi koyar |
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
export function MeyveSecimi() {
return (
<Select>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Bir meyve seçin" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Meyveler</SelectLabel>
<SelectItem value="apple">Elma</SelectItem>
<SelectItem value="banana">Muz</SelectItem>
<SelectItem value="blueberry">Yaban mersini</SelectItem>
<SelectItem value="grapes">Üzüm</SelectItem>
<SelectItem value="pineapple">Ananas</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
)
}Bu örnek belgedeki select-demo dosyasının Türkçe etiketli hâlidir. Değerler (value) kodda kullanılacak kısa anahtarlardır, ekranda görünen metin ise SelectItem'ın içeriğidir. Tetikleyicideki w-[180px] sınıfı önemlidir: kaynakta tetikleyici w-fit sınıfını alır, yani genişlik vermezseniz seçili metnin uzunluğuna göre daralıp genişler. Sabit bir genişlik vermek, farklı uzunluktaki seçenekler arasında geçerken düzenin oynamasını önler.
Uzun listeler: gruplar ve kaydırma
Belgedeki tek ek örnek "Scrollable"dır: saat dilimleri kıtalara göre birkaç SelectGroup içinde listelenir. Kaynakta SelectContent, yüksekliğini Radix'in verdiği --radix-select-content-available-height değişkeniyle sınırlar ve taşma olduğunda dikey kaydırmaya izin verir. Listenin üstüne ve altına yukarı ve aşağı oklu kaydırma butonlarını (SelectScrollUpButton, SelectScrollDownButton) bileşen kendisi ekler; bunları sizin yazmanız gerekmez.
<Select>
<SelectTrigger className="w-[280px]">
<SelectValue placeholder="Saat dilimi seçin" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Avrupa</SelectLabel>
<SelectItem value="gmt">Greenwich Mean Time (GMT)</SelectItem>
<SelectItem value="cet">Central European Time (CET)</SelectItem>
<SelectItem value="eet">Eastern European Time (EET)</SelectItem>
</SelectGroup>
<SelectSeparator />
<SelectGroup>
<SelectLabel>Asya</SelectLabel>
<SelectItem value="ist">India Standard Time (IST)</SelectItem>
<SelectItem value="jst">Japan Standard Time (JST)</SelectItem>
</SelectGroup>
</SelectContent>
</Select>Grup başlıkları SelectLabel ile yazılır ve kaynakta küçük, soluk bir metin olarak (text-muted-foreground text-xs) gösterilir. Başlık seçilebilir bir öğe değildir; yalnızca altındaki seçenekleri adlandırır. SelectSeparator kullanmak isteğe bağlıdır, bu örnekte iki grubu görsel olarak ayırmak için eklendi (bu durumda SelectSeparator'ı da import etmeyi unutmayın).
Kontrollü Select ve tetikleyici boyutu
Seçili değeri React durumunda tutmak için value ve onValueChange özellikleri Select köküne verilir. Depodaki dashboard bloğu, aynı durumu geniş ekranda bir ToggleGroup'a, dar ekranda bir Select'e bağlar ve tetikleyiciye size="sm" verir. Kaynakta size yalnızca iki değer alır: default (9 birim yükseklik) ve sm (8 birim).
"use client"
import * as React from "react"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
export function DonemSecici() {
const [timeRange, setTimeRange] = React.useState("90d")
return (
<Select value={timeRange} onValueChange={setTimeRange}>
<SelectTrigger className="w-40" size="sm" aria-label="Dönem seçin">
<SelectValue placeholder="Son 3 ay" />
</SelectTrigger>
<SelectContent className="rounded-xl">
<SelectItem value="90d" className="rounded-lg">Son 3 ay</SelectItem>
<SelectItem value="30d" className="rounded-lg">Son 30 gün</SelectItem>
<SelectItem value="7d" className="rounded-lg">Son 7 gün</SelectItem>
</SelectContent>
</Select>
)
}Dikkat edilecek iki nokta var. Birincisi, olay adı onValueChange'dir ve doğrudan yeni değeri (bir string) verir; event.target.value okumazsınız. İkincisi, tetikleyicinin görünür bir etiketi yoksa bu örnekteki gibi aria-label vermek ekran okuyucuya alanın amacını söyler. ButtonGroup belgesindeki para birimi örneğinde ise SelectValue yerine seçili değer doğrudan tetikleyicinin içine yazılır; bu da kontrollü kullanımın sağladığı bir esnekliktir.
Seçeneklerin içeriği ve görünümü
SelectItem yalnızca düz metin almak zorunda değildir. ButtonGroup belgesindeki para birimi örneği, her seçeneğin içine sembolü ve yanına text-muted-foreground sınıflı bir span ile para biriminin adını yazar. Kaynakta öğe sınıflarında SVG ikonlar için de kurallar vardır: renk sınıfı verilmemiş ikonlar soluk renkte, boyut sınıfı verilmemiş ikonlar 4 birim boyutta gösterilir. Seçili öğenin sağında bir CheckIcon çıkar; bunun için öğenin sağ dolgusu (pr-8) baştan ayrılmıştır, böylece onay işareti metnin üstüne binmez.
<SelectContent className="min-w-24">
<SelectItem value="TRY">
₺ <span className="text-muted-foreground">Türk lirası</span>
</SelectItem>
<SelectItem value="EUR">
€ <span className="text-muted-foreground">Euro</span>
</SelectItem>
<SelectItem value="USD" disabled>
$ <span className="text-muted-foreground">ABD doları</span>
</SelectItem>
</SelectContent>Son öğedeki disabled, Radix'in öğeye data-disabled yazmasını sağlar; kaynaktaki data-[disabled]:opacity-50 ve data-[disabled]:pointer-events-none sınıfları öğeyi soluklaştırıp tıklanamaz yapar. Listenin köşelerini ya da genişliğini değiştirmek için SelectContent'e, tek tek öğeleri değiştirmek için SelectItem'a className verirsiniz; dashboard bloğu da listeye rounded-xl, öğelere rounded-lg vererek bunu yapar.
position: item-aligned ve popper

SelectContent, Radix'in position özelliğini alır ve kaynakta varsayılan değer "item-aligned"'dır; align için varsayılan "center"'dır. "popper" değerini verdiğinizde kaynak iki şey ekler: listeyi açıldığı yöne göre biraz kaydıran translate sınıfları ve listenin en az tetikleyici kadar geniş olmasını sağlayan min-w-[var(--radix-select-trigger-width)] kuralı. İki modun konumlandırma davranışının ayrıntısı Radix Select belgesinde anlatılır; shadcn/ui belgeleri bu konuda ayrıca açıklama yapmaz. React Hook Form sayfasındaki select örneği position="item-aligned" değerini açıkça yazar.
<SelectContent position="popper">
<SelectItem value="tr">Türkçe</SelectItem>
<SelectItem value="en">English</SelectItem>
</SelectContent>Select ile form
React Hook Form sayfası Select için iki kural verir: field.value ve field.onChange değerlerini Select köküne verin; hatayı göstermek için SelectTrigger'a aria-invalid, onu saran Field bileşenine data-invalid ekleyin. Kaynaktaki aria-invalid:border-destructive sınıfı tetikleyicinin çerçevesini hata rengine boyar.
<Controller
name="language"
control={form.control}
render={({ field, fieldState }) => (
<Field orientation="responsive" data-invalid={fieldState.invalid}>
<FieldContent>
<FieldLabel htmlFor="form-rhf-select-language">Konuşulan dil</FieldLabel>
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
</FieldContent>
<Select name={field.name} value={field.value} onValueChange={field.onChange}>
<SelectTrigger
id="form-rhf-select-language"
aria-invalid={fieldState.invalid}
className="min-w-[120px]"
>
<SelectValue placeholder="Seçin" />
</SelectTrigger>
<SelectContent position="item-aligned">
<SelectItem value="auto">Otomatik</SelectItem>
<SelectItem value="en">English</SelectItem>
</SelectContent>
</Select>
</Field>
)}
/>Bu kod parçası belgedeki örneğin açıklama satırı çıkarılmış hâlidir; şema, useForm kurulumu ve Field bileşenleri React Hook Form ve Zod yazısında, alan düzeni Field bileşeni yazısında anlatılıyor.
NativeSelect: tarayıcının kendi select öğesi
NativeSelect, npx shadcn@latest add native-select ile eklenir ve belgelerde elle kurulacak bir paket listelenmez; kaynak yalnızca lucide-react ikonunu ve cn() yardımcısını kullanır. Üç parçası vardır: NativeSelect (HTML select), NativeSelectOption (option) ve NativeSelectOptGroup (optgroup). Hepsi aldıkları ek özellikleri doğrudan bu HTML öğelerine geçirir, yani name, value, onChange, required bildiğiniz gibi çalışır.
npx shadcn@latest add native-selectimport {
NativeSelect,
NativeSelectOptGroup,
NativeSelectOption,
} from "@/components/ui/native-select"
export function YemekSecimi() {
return (
<NativeSelect>
<NativeSelectOption value="">Bir yiyecek seçin</NativeSelectOption>
<NativeSelectOptGroup label="Meyveler">
<NativeSelectOption value="apple">Elma</NativeSelectOption>
<NativeSelectOption value="banana">Muz</NativeSelectOption>
</NativeSelectOptGroup>
<NativeSelectOptGroup label="Sebzeler">
<NativeSelectOption value="carrot">Havuç</NativeSelectOption>
<NativeSelectOption value="spinach" disabled>
Ispanak
</NativeSelectOption>
</NativeSelectOptGroup>
</NativeSelect>
)
}Belgedeki örneklerde ilk seçenek value="" ile yazılır ve yer tutucu görevi görür; NativeSelect'te Radix Select'teki gibi ayrı bir placeholder parçası yoktur. Tek bir seçeneği disabled ile, bütün grubu NativeSelectOptGroup'a disabled vererek, tüm listeyi de NativeSelect'e disabled vererek devre dışı bırakabilirsiniz. Kaynakta bütün liste devre dışıyken saran öğe has-[select:disabled]:opacity-50 ile soluklaşır.
NativeSelect kaynağındaki ayrıntılar
Kaynağa bakınca iki önemli ayrıntı görülür. Birincisi, select öğesi data-slot="native-select-wrapper" taşıyan bir div ile sarılır ve aşağı ok ikonu bu kapsayıcının içinde, select'in üstüne mutlak konumla yerleştirilir. Tarayıcının kendi okunu gizlemek için select'e appearance-none verilir. Sizin verdiğiniz className ise kapsayıcıya değil select öğesine uygulanır; kapsayıcının sınıflarını (relative w-fit) değiştirmek isterseniz native-select.tsx dosyasını düzenlemeniz gerekir.
İkincisi, HTML select öğesinin size adlı kendi bir özelliği vardır (görünen satır sayısı). Kaynak bunu türden çıkarır ve yerine "sm" ile "default" değerlerini alan kendi size özelliğini koyar; sm değeri yüksekliği 8 birime indirir. Yani NativeSelect'te size, HTML'deki anlamıyla değil Select tetikleyicisindeki anlamıyla çalışır.
<NativeSelect size="sm" aria-label="Öncelik">
<NativeSelectOption value="low">Düşük</NativeSelectOption>
<NativeSelectOption value="high">Yüksek</NativeSelectOption>
</NativeSelect>Hata durumu ve erişilebilirlik
Hatalı bir alanı göstermek için belge, aria-invalid özniteliğini kullanmayı gösterir; kaynakta bu öznitelik çerçeveyi ve halkayı hata rengine çevirir. Erişilebilirlik bölümü ise dört not düşer: bileşen yerel select öğesinin bütün erişilebilirlik özelliklerini korur, ekran okuyucular seçenekler arasında ok tuşlarıyla gezebilir, ok ikonu tekrar okunmasın diye aria-hidden="true" ile işaretlenmiştir ve gerektiğinde ek bağlam için aria-label ya da aria-labelledby kullanılabilir.
<NativeSelect aria-invalid="true" aria-label="Ülke">
<NativeSelectOption value="">Bir ülke seçin</NativeSelectOption>
<NativeSelectOption value="tr">Türkiye</NativeSelectOption>
<NativeSelectOption value="de">Almanya</NativeSelectOption>
</NativeSelect>Etiketi görünür olarak göstermek isterseniz aria-label yerine bir Label bileşeni ve htmlFor ile id eşleşmesi kullanmak daha iyidir. Belge sayfası NativeSelect'in React Hook Form ve InputGroup ile birlikte kullanılabildiğini de örnek başlıklarıyla belirtir. Erişilebilir etiketleme için ARIA yazısına bakabilirsiniz.
Mini örnek: etiketli ve kontrollü NativeSelect
NativeSelect gerçek bir select öğesi olduğu için kontrollü kullanımda React'in alışılmış value ve onChange ikilisi kullanılır; Radix Select'teki gibi doğrudan değer değil, bir olay nesnesi gelir ve değeri event.target.value içinden okursunuz. Aşağıdaki örnek görünür bir etiketle birlikte öncelik seçtirir ve seçimi altında gösterir:
"use client"
import { useState } from "react"
import { Label } from "@/components/ui/label"
import {
NativeSelect,
NativeSelectOption,
} from "@/components/ui/native-select"
export function OncelikSecimi() {
const [oncelik, setOncelik] = useState("")
return (
<div className="grid gap-3">
<Label htmlFor="oncelik">Öncelik</Label>
<NativeSelect
id="oncelik"
value={oncelik}
onChange={(event) => setOncelik(event.target.value)}
aria-invalid={oncelik === "" ? "true" : undefined}
>
<NativeSelectOption value="">Öncelik seçin</NativeSelectOption>
<NativeSelectOption value="low">Düşük</NativeSelectOption>
<NativeSelectOption value="medium">Orta</NativeSelectOption>
<NativeSelectOption value="high">Yüksek</NativeSelectOption>
</NativeSelect>
<p className="text-muted-foreground text-sm">
Seçilen: {oncelik || "henüz yok"}
</p>
</div>
)
}Burada aria-invalid, seçim yapılmadığı sürece alanı hata rengiyle çerçeveler; gerçek bir formda bu değeri doğrulama sonucuna bağlarsınız. id özelliği wrapper'a değil doğrudan select öğesine gittiği için Label bağlantısı sorunsuz çalışır. Seçenek listesinin açıldığı görünüm tarayıcıya ve işletim sistemine aittir; bu, NativeSelect'i seçmenin hem avantajı hem de sınırıdır.
Select mi, NativeSelect mi?

| Ölçüt | Select | NativeSelect |
|---|---|---|
| Altyapı | Radix Select, portal içinde özel liste | Tarayıcının select öğesi |
| Ek paket | @radix-ui/react-select | Belgede listelenmiyor |
| Liste görünümü | Tamamen stillendirilebilir, animasyonlu | Açılan liste tarayıcı ve işletim sistemine ait |
| Yer tutucu | SelectValue placeholder | value boş ilk seçenek |
| Değişiklik olayı | onValueChange (string) | onChange (HTML olayı) |
| Gruplama | SelectGroup, SelectLabel | NativeSelectOptGroup label |
| Belgenin önerisi | Özel stil, animasyon, karmaşık etkileşim | Yerel davranış, performans, mobil uyum |
Kısa bir karar yolu: seçenekler düz metinse ve tarayıcının kendi açılır listesi yeterliyse NativeSelect işinizi görür. Seçeneklerde ikon, açıklama satırı ya da tutarlı bir tasarım isteniyorsa Select seçin. Kullanıcının yazarak arama yapması gerekiyorsa ikisi de uygun değildir; Combobox ya da daha geniş komut listeleri için Command bileşenine geçin.
Sık yapılan hatalar
- SelectValue'yu unutmak. Tetikleyicinin içinde
SelectValueyoksa seçili değer ya da yer tutucu görünmez; yalnızca ok ikonu kalır. - Select'te onChange kullanmak. Radix tabanlı Select
onValueChangeile çalışır ve doğrudan değeri verir. - Tetikleyiciye genişlik vermemek.
w-fitvarsayılanı yüzünden genişlik seçili metne göre değişir; belgedeki gibiw-[180px]benzeri bir genişlik verin. - NativeSelect'te className'i kapsayıcıya gidiyor sanmak. Sınıflar
selectöğesine uygulanır; kapsayıcı için dosyayı düzenleyin. - NativeSelect size değerine sayı vermek. Bu bileşende
sizeyalnızca"sm"ya da"default"alır. - Arama gerektiren listede Select kullanmak. Yüzlerce seçenek için Select'in içinde arama alanı yoktur; Combobox kullanın.
Sık Sorulan Sorular
Select içinde arama yapılabilir mi?
Select bileşeninin kendisinde arama alanı yoktur. Belgelerdeki aranabilir liste çözümü, Popover ve Command bileşenlerini birleştiren Combobox'tır; ayrıntısı Combobox yazısında.
Birden çok değer seçtiren bir Select var mı?
shadcn/ui belgelerindeki Select tek değer seçer. Birden çok seçim için belgelerde checkbox listeleri ve ToggleGroup ile type="multiple" kullanımı gösterilir; bunlar Checkbox ve Radio yazısında ve Toggle Group yazısında anlatılıyor.
NativeSelect ne zaman eklendi?
Depo kopyası 19 Aralık 2025 tarihli ve bileşen bu kopyada mevcut; değişiklik günlüğünün Ekim 2025 bileşen listesinde ise NativeSelect yer almıyor. Kesin eklenme tarihini belgeler belirtmediği için burada bir tarih vermiyoruz.
Select listesi neden diğer öğelerin üstünde görünüyor?
SelectContent, kaynakta SelectPrimitive.Portal içinde render edilir ve z-50 sınıfını taşır; yani liste DOM'da sayfanın sonuna taşınır ve diğer öğelerin üzerinde görünür. Bu yüzden liste, onu açan tetikleyicinin kapsayıcısından bağımsız olarak çizilir.
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: shadcn/ui öğrenme rehberi · Combobox · Checkbox, Radio, Switch, Slider · Field bileşeni · React Hook Form ve Zod