Öğe
Bildirim akışları, ayar listeleri ve dosya satırları için medya, başlık, açıklama ve eylem alanlarına sahip esnek bir satır — neobrütalist tarzında.
import { BadgeCheckIcon, ChevronRightIcon } from "lucide-react"
import { Button } from "@/components/ui/button"Item, her uygulamanın er ya da geç ihtiyaç duyduğu “nesne listesi” deseni için adlandırılmış yuvalara — medya, içerik, eylemler — sahip bir flex satırıdır. Altta headless bir primitif yoktur; yalnızca stillendirilmiş öğeler (artı render prop'u için Base UI useRender) neobrütalist reçeteyle tamamlanmıştır: 2 piksellik bir kenarlık — outline varyantında görünür — ve keskin, ofsetli bir odak halkası.
Şu durumlarda tercih edin:
- Bildirim ve etkinlik akışları — her satırda avatar, mesaj, zaman damgası ve bir kapatma veya eylem düğmesi.
- Ayar ve entegrasyon listeleri — simge, ad, durum satırı; uç tarafta bir anahtar veya düğme.
- Dosya gezginleri ve arama sonuçları — küçük resim veya simge artı meta veriler;
renderile tüm satır bir bağlantıya dönüşür.
Item bileşeni, hemen hemen her tür içeriği barındırabilen sade bir flex kapsayıcısıdır. Bir başlık, açıklama ve eylemler göstermek için kullanın. Bir öğe listesi oluşturmak için ItemGroup bileşeniyle gruplayın.
Kurulum#
pnpm dlx shadcn@latest add https://neobrutalism.com/r/base/item.jsonnpx shadcn@latest add https://neobrutalism.com/r/base/item.jsonyarn dlx shadcn@latest add https://neobrutalism.com/r/base/item.jsonbunx --bun shadcn@latest add https://neobrutalism.com/r/base/item.json
Aşağıdaki kodu kopyalayıp projenize yapıştırın.
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { Slot } from "radix-ui"
import { cn } from "@/lib/utils"
import { Separator } from "@/components/ui/separator"
function ItemGroup({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
role="list"
data-slot="item-group"
className={cn(
"group/item-group flex w-full flex-col gap-4 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2",
className
)}
{...props}
/>
)
}
function ItemSeparator({
className,
...props
}: React.ComponentProps<typeof Separator>) {
return (
<Separator
data-slot="item-separator"
orientation="horizontal"
className={cn("my-2", className)}
{...props}
/>
)
}
const itemVariants = cva(
"group/item flex w-full flex-wrap items-center rounded border-2 text-sm transition-colors duration-100 outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary [a]:transition-colors [a]:hover:bg-accent",
{
variants: {
variant: {
default: "border-transparent",
outline: "border-border",
muted: "border-transparent bg-muted/50",
},
size: {
default: "gap-2.5 px-3 py-2.5",
sm: "gap-2.5 px-3 py-2.5",
xs: "gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
function Item({
className,
variant = "default",
size = "default",
asChild = false,
...props
}: React.ComponentProps<"div"> &
VariantProps<typeof itemVariants> & { asChild?: boolean }) {
const Comp = asChild ? Slot.Root : "div"
return (
<Comp
data-slot="item"
data-variant={variant}
data-size={size}
className={cn(itemVariants({ variant, size, className }))}
{...props}
/>
)
}
const itemMediaVariants = cva(
"flex shrink-0 items-center justify-center gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start [&_svg]:pointer-events-none",
{
variants: {
variant: {
default: "bg-transparent",
icon: "[&_svg:not([class*='size-'])]:size-4",
image:
"size-10 overflow-hidden rounded-sm group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover",
},
},
defaultVariants: {
variant: "default",
},
}
)
function ItemMedia({
className,
variant = "default",
...props
}: React.ComponentProps<"div"> & VariantProps<typeof itemMediaVariants>) {
return (
<div
data-slot="item-media"
data-variant={variant}
className={cn(itemMediaVariants({ variant, className }))}
{...props}
/>
)
}
function ItemContent({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="item-content"
className={cn(
"flex flex-1 flex-col gap-1 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none",
className
)}
{...props}
/>
)
}
function ItemTitle({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="item-title"
className={cn(
"line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-medium underline-offset-4",
className
)}
{...props}
/>
)
}
function ItemDescription({ className, ...props }: React.ComponentProps<"p">) {
return (
<p
data-slot="item-description"
className={cn(
"line-clamp-2 text-left text-sm leading-normal font-normal text-muted-foreground group-data-[size=xs]/item:text-xs [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
className
)}
{...props}
/>
)
}
function ItemActions({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="item-actions"
className={cn("flex items-center gap-2", className)}
{...props}
/>
)
}
function ItemHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="item-header"
className={cn(
"flex basis-full items-center justify-between gap-2",
className
)}
{...props}
/>
)
}
function ItemFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="item-footer"
className={cn(
"flex basis-full items-center justify-between gap-2",
className
)}
{...props}
/>
)
}
export {
Item,
ItemMedia,
ItemContent,
ItemActions,
ItemGroup,
ItemSeparator,
ItemTitle,
ItemDescription,
ItemHeader,
ItemFooter,
}
İçe aktarma yollarını proje kurulumunuza göre güncelleyin.
Kullanım#
import {
Item,
ItemActions,
ItemContent,
ItemDescription,
ItemMedia,
ItemTitle,
} from "@/components/ui/item"<Item>
<ItemMedia variant="icon">
<Icon />
</ItemMedia>
<ItemContent>
<ItemTitle>Title</ItemTitle>
<ItemDescription>Description</ItemDescription>
</ItemContent>
<ItemActions>
<Button>Action</Button>
</ItemActions>
</Item>Kompozisyon#
Bir Item oluşturmak için aşağıdaki kompozisyonu kullanın:
ItemGroup
└── Item
├── ItemHeader
├── ItemMedia
├── ItemContent
│ ├── ItemTitle
│ └── ItemDescription
├── ItemActions
└── ItemFooterItem vs Field#
Onay kutusu, giriş, radyo düğmesi veya select gibi bir form girişi göstermeniz gerekiyorsa Field kullanın.
Yalnızca başlık, açıklama ve eylemler gibi içerik göstermeniz gerekiyorsa Item kullanın.
Variant#
Öğenin görsel stilini değiştirmek için variant prop'unu kullanın.
import { InboxIcon } from "lucide-react"
import {Size#
Öğenin boyutunu değiştirmek için size prop'unu kullanın. Kullanılabilir boyutlar default, sm ve xs'dir.
import { InboxIcon } from "lucide-react"
import {Örnekler#
Simge#
Bir simge göstermek için ItemMedia'yı variant="icon" ile kullanın.
import { ShieldAlertIcon } from "lucide-react"
import { Button } from "@/components/ui/button"Avatar#
Bir avatar göstermek için ItemMedia'yı variant="avatar" ile kullanabilirsiniz.
import { Plus } from "lucide-react"
import {Görsel#
Bir görsel göstermek için ItemMedia'yı variant="image" ile kullanın.
import Image from "next/image"
import {Grup#
İlgili öğeleri bir arada gruplamak için ItemGroup kullanın.
import * as React from "react"
import { PlusIcon } from "lucide-react"
Üst Bilgi#
Öğe içeriğinin üstüne bir üst bilgi eklemek için ItemHeader kullanın.
import Image from "next/image"
import {Bağlantı#
Öğeyi bir bağlantı olarak render etmek için render prop'unu kullanın. Hover ve focus durumları anchor öğesine uygulanır.
import { ChevronRightIcon, ExternalLinkIcon } from "lucide-react"
import {<Item render={<a href="/dashboard" />}>
<ItemMedia variant="icon">
<HomeIcon />
</ItemMedia>
<ItemContent>
<ItemTitle>Dashboard</ItemTitle>
<ItemDescription>Overview of your account and activity.</ItemDescription>
</ItemContent>
</Item>Dropdown#
"use client"
import { ChevronDownIcon } from "lucide-react"RTL#
Neobrutalism'de RTL desteğini etkinleştirmek için RTL yapılandırma kılavuzuna bakın.
"use client"
import * as React from "react"Erişilebilirlik#
Item yalnızca görseldir — kendine ait ARIA bağlantısı olmayan stillendirilmiş öğelerden oluşur; yine de ItemGroup role="list" olarak işlenir (liste yapısının duyurulması gerekiyorsa her Item öğesine role="listitem" ekleyin). Etkileşimli satırlar için tıklama işleyicisini div'e koymayın — yerel odak ve klavye davranışı kazanması için render prop'u aracılığıyla gerçek bir <a> veya <button> işleyin; görünür odak halkası zaten stillendirilmiştir. Dekoratif simge medyasını aria-hidden ile işaretleyin ve resim medyasına anlamlı alt metni verin.
API Referansı#
Item#
Medya, başlık, açıklama ve eylemlerle içerik göstermeye yarayan ana bileşen.
| Prop | Type | Default |
|---|---|---|
variant | "default" | "outline" | "muted" | "default" |
size | "default" | "sm" | "xs" | "default" |
render | React.ReactElement |
ItemGroup#
İlgili öğeleri tutarlı bir stille bir arada gruplayan bir kapsayıcı.
<ItemGroup>
<Item />
<Item />
</ItemGroup>ItemSeparator#
Bir gruptaki öğeler arasındaki bir ayırıcı.
<ItemGroup>
<Item />
<ItemSeparator />
<Item />
</ItemGroup>ItemMedia#
Simge, görsel veya avatar gibi medya içeriği göstermek için ItemMedia kullanın.
| Prop | Type | Default |
|---|---|---|
variant | "default" | "icon" | "image" | "default" |
<ItemMedia variant="icon">
<Icon />
</ItemMedia><ItemMedia variant="image">
<img src="..." alt="..." />
</ItemMedia>ItemContent#
Öğenin başlığını ve açıklamasını sarar.
<ItemContent>
<ItemTitle>Title</ItemTitle>
<ItemDescription>Description</ItemDescription>
</ItemContent>ItemTitle#
Öğenin başlığını gösterir.
<ItemTitle>Item Title</ItemTitle>ItemDescription#
Öğenin açıklamasını gösterir.
<ItemDescription>Item description</ItemDescription>ItemActions#
Eylem düğmeleri veya diğer etkileşimli öğeler için kapsayıcı.
<ItemActions>
<Button>Action</Button>
</ItemActions>ItemHeader#
Öğe içeriğinin üstünde bir üst bilgi gösterir.
<Item>
<ItemHeader>Header</ItemHeader>
<ItemContent>...</ItemContent>
</Item>ItemFooter#
Öğe içeriğinin altında bir alt bilgi gösterir.
<Item>
<ItemContent>...</ItemContent>
<ItemFooter>Footer</ItemFooter>
</Item>