HextaUI

Item

Listeler, ayarlar ve seçiciler için medya, metin ve eylemlerden oluşan bir satır; gruplanmış bir yüzey ve satırlar arasında kayan bir hover vurgusu içerir.

import {
  IconBell,
  IconDeviceDesktop,
  IconKey,
  IconUserCircle,
} from "@tabler/icons-react"

import {
  Item,
  ItemChevron,
  ItemContent,
  ItemDescription,
  ItemGroup,
  ItemMedia,
  ItemTitle,
  type ItemMediaTone,
} from "@/components/ui/item"

const settings: {
  href: string
  icon: typeof IconBell
  title: string
  tone: ItemMediaTone
  description: string
}[] = [
  {
    href: "#profile",
    icon: IconUserCircle,
    title: "Profile",
    tone: "gray",
    description: "Name, photo and handle",
  },
  {
    href: "#notifications",
    icon: IconBell,
    title: "Notifications",
    tone: "red",
    description: "Mentions, replies and digests",
  },
  {
    href: "#security",
    icon: IconKey,
    title: "Password and passkeys",
    tone: "green",
    description: "Two passkeys, last used today",
  },
  {
    href: "#sessions",
    icon: IconDeviceDesktop,
    title: "Sessions",
    tone: "blue",
    description: "Signed in on 3 devices",
  },
]

export function ItemDemo() {
  return (
    <ItemGroup variant="grouped" className="max-w-sm">
      {settings.map((setting) => (
        <Item key={setting.href} size="sm" render={<a href={setting.href} />}>
          <ItemMedia variant="icon" tone={setting.tone}>
            <setting.icon />
          </ItemMedia>
          <ItemContent>
            <ItemTitle>{setting.title}</ItemTitle>
            <ItemDescription>{setting.description}</ItemDescription>
          </ItemContent>
          <ItemChevron />
        </Item>
      ))}
    </ItemGroup>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/item.json

Bileşeni, HextaUI tema token'larını ve bileşenin bağımlı olduğu tüm HextaUI bileşenlerini ekler.

import {
  Item,
  ItemActions,
  ItemChevron,
  ItemContent,
  ItemDescription,
  ItemGroup,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item"
<ItemGroup variant="grouped">
  <Item render={<a href="/settings/profile" />}>
    <ItemMedia variant="icon">
      <IconUserCircle />
    </ItemMedia>
    <ItemContent>
      <ItemTitle>Profile</ItemTitle>
      <ItemDescription>Name, photo and handle</ItemDescription>
    </ItemContent>
    <ItemChevron />
  </Item>
</ItemGroup>

iOS Settings gibi renkli karolar için simge medyasına bir tone verin veya nötr bir karo için ayarlamadan bırakın. Bir öğe, render ile bağlantı, düğme veya etiket olarak render edildiğinde etkileşimli olur. Yalnızca o zaman üzerine gelme, basma ve odak stillerini alır; böylece statik satırlar asla tıklanabilirmiş gibi davranmaz.

ItemGroup
├── Item
│   ├── ItemHeader
│   ├── ItemMedia
│   ├── ItemContent
│   │   ├── ItemTitle
│   │   └── ItemDescription
│   ├── ItemActions
│   ├── ItemChevron
│   └── ItemFooter
└── ItemSeparator

Gruplanmış

variant="grouped" öğeleri tek bir yüzeye yerleştirir. Ayırıcılar sizin için çizilir ve metne göre girintilenir, ilk ve son satırlar dış köşelere sahip olur, üzerine gelinen veya odaklanılan satırın yanındaki ayırıcılar kaybolur.

"use client"

import * as React from "react"
import { IconCheck } from "@tabler/icons-react"

import {
  Item,
  ItemContent,
  ItemDescription,
  ItemGroup,
  ItemTitle,
} from "@/components/ui/item"

const themes = [
  { id: "system", title: "System", description: "Follow your device" },
  { id: "light", title: "Light", description: "Always light" },
  { id: "dark", title: "Dark", description: "Always dark" },
]

export function ItemPressed() {
  const [theme, setTheme] = React.useState("system")

  return (
    <ItemGroup variant="grouped" className="max-w-sm">
      {themes.map((option) => (
        <Item
          key={option.id}
          size="sm"
          render={<button type="button" />}
          aria-pressed={theme === option.id}
          onClick={() => setTheme(option.id)}
        >
          <ItemContent>
            <ItemTitle>{option.title}</ItemTitle>
            <ItemDescription>{option.description}</ItemDescription>
          </ItemContent>
          {theme === option.id && (
            <IconCheck className="size-4 text-foreground" aria-hidden="true" />
          )}
        </Item>
      ))}
    </ItemGroup>
  )
}

Üzerine gelme vurgusu

Bir gruptaki etkileşimli öğeler, işaretçinin altındaki satıra kayan ve köşelerini alan tek bir vurguyu paylaşır. Yalnızca fareyi veya kalemi izler, dokunmayı asla; highlight={false} ile kapatın. Görsel medya köşeleri satırla eş merkezlidir.

import {
  Item,
  ItemChevron,
  ItemContent,
  ItemDescription,
  ItemGroup,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item"

const albums = [
  {
    title: "Night Drive",
    artist: "Lune Avenue",
    src: "https://images.unsplash.com/photo-1514525253161-7a46d19cd819?w=120&h=120&fit=crop",
  },
  {
    title: "Paper Gardens",
    artist: "Mara Lin",
    src: "https://images.unsplash.com/photo-1493225457124-a3eb161ffa5f?w=120&h=120&fit=crop",
  },
  {
    title: "Low Tide",
    artist: "The Harbour",
    src: "https://images.unsplash.com/photo-1511379938547-c1f69419868d?w=120&h=120&fit=crop",
  },
]

export function ItemImage() {
  return (
    <ItemGroup className="max-w-sm">
      {albums.map((album) => (
        <Item key={album.title} size="sm" render={<a href="#" />}>
          <ItemMedia variant="image">
            <img src={album.src} alt="" width={40} height={40} />
          </ItemMedia>
          <ItemContent>
            <ItemTitle>{album.title}</ItemTitle>
            <ItemDescription>{album.artist}</ItemDescription>
          </ItemContent>
          <ItemChevron />
        </Item>
      ))}
    </ItemGroup>
  )
}

Seçilebilir

Bir öğeyi Checkbox çevresinde bir <label> olarak işlerseniz tüm satır onu açıp kapatır. İşaretli bir denetim ya da öğedeki aria-selected, aria-checked veya aria-pressed, satırı seçili olarak işaretler.

import { Checkbox } from "@/components/ui/checkbox"
import {
  Item,
  ItemContent,
  ItemDescription,
  ItemGroup,
  ItemTitle,
} from "@/components/ui/item"

const plans = [
  {
    id: "analytics",
    title: "Analytics",
    description: "Page views and funnels",
  },
  { id: "backups", title: "Daily backups", description: "Kept for 30 days" },
  { id: "sso", title: "Single sign-on", description: "SAML and OIDC" },
]

export function ItemSelectable() {
  return (
    <ItemGroup className="max-w-sm">
      {plans.map((plan, index) => (
        <Item key={plan.id} variant="outline" size="sm" render={<label />}>
          <Checkbox
            name="addons"
            value={plan.id}
            defaultChecked={index === 0}
          />
          <ItemContent>
            <ItemTitle>{plan.title}</ItemTitle>
            <ItemDescription>{plan.description}</ItemDescription>
          </ItemContent>
        </Item>
      ))}
    </ItemGroup>
  )
}

Varyantlar

default yüzeysizdir, outline ince bir çizgi çizer, muted yumuşak bir dolgu üzerinde durur.

import { IconFileText } from "@tabler/icons-react"

import { Button } from "@/components/ui/button"
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item"

const variants = ["default", "outline", "muted"] as const

export function ItemVariants() {
  return (
    <div className="flex w-full max-w-md flex-col gap-4">
      {variants.map((variant) => (
        <Item key={variant} variant={variant}>
          <ItemMedia variant="icon">
            <IconFileText />
          </ItemMedia>
          <ItemContent>
            <ItemTitle>Quarterly report.pdf</ItemTitle>
            <ItemDescription>2.4 MB · {variant}</ItemDescription>
          </ItemContent>
          <ItemActions>
            <Button variant="outline" size="sm">
              Open
            </Button>
          </ItemActions>
        </Item>
      ))}
    </div>
  )
}

Boyutlar

size dolgu, boşluk, köşe yarıçapı ve medyayı birlikte ölçekler. Grup, boşluğunu buna uyacak şekilde daraltır.

import { IconMusic } from "@tabler/icons-react"

import {
  Item,
  ItemContent,
  ItemDescription,
  ItemGroup,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item"

const sizes = ["default", "sm", "xs"] as const

export function ItemSizes() {
  return (
    <ItemGroup className="max-w-sm">
      {sizes.map((size) => (
        <Item key={size} size={size} variant="outline">
          <ItemMedia variant="icon">
            <IconMusic />
          </ItemMedia>
          <ItemContent>
            <ItemTitle>Size {size}</ItemTitle>
            <ItemDescription>
              Padding, gap and media scale together.
            </ItemDescription>
          </ItemContent>
        </Item>
      ))}
    </ItemGroup>
  )
}

Avatar

Varsayılan <ItemMedia /> yalnızca içeriğini ortalar; bu yüzden Avatar veya AvatarGroup doğrudan yerleşir.

import { IconPlus } from "@tabler/icons-react"

import {
  Avatar,
  AvatarFallback,
  AvatarGroup,
  AvatarImage,
} from "@/components/ui/avatar"
import { Button } from "@/components/ui/button"
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item"

const team = [
  { handle: "preetsuthar17", initials: "PS" },
  { handle: "emilkowalski", initials: "EK" },
  { handle: "rauchg", initials: "GR" },
]

export function ItemAvatar() {
  return (
    <div className="flex w-full max-w-lg flex-col gap-6">
      <Item variant="outline">
        <ItemMedia>
          <Avatar size="lg">
            <AvatarImage src="https://github.com/preetsuthar17.png" alt="" />
            <AvatarFallback>PS</AvatarFallback>
          </Avatar>
        </ItemMedia>
        <ItemContent>
          <ItemTitle>Preet Suthar</ItemTitle>
          <ItemDescription>Maintainer of HextaUI</ItemDescription>
        </ItemContent>
        <ItemActions>
          <Button
            variant="outline"
            size="icon-sm"

            aria-label="Invite Preet Suthar"
          >
            <IconPlus />
          </Button>
        </ItemActions>
      </Item>
      <Item variant="outline">
        <ItemMedia>
          <AvatarGroup>
            {team.map((person) => (
              <Avatar key={person.handle}>
                <AvatarImage
                  src={`https://github.com/${person.handle}.png`}
                  alt=""
                />
                <AvatarFallback>{person.initials}</AvatarFallback>
              </Avatar>
            ))}
          </AvatarGroup>
        </ItemMedia>
        <ItemContent>
          <ItemTitle>No team members</ItemTitle>
          <ItemDescription>Invite your team to collaborate.</ItemDescription>
        </ItemContent>
        <ItemActions>
          <Button size="sm" variant="outline">
            Invite
          </Button>
        </ItemActions>
      </Item>
    </div>
  )
}

Kişiler

Gruplanmış bir kişi listesi. Ayırıcılar, medya slotunda ne olursa olsun metnin başladığı yerden başlar; böylece adların altında hizalanır.

import { IconPlus } from "@tabler/icons-react"

import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Button } from "@/components/ui/button"
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemGroup,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item"

const people = [
  { handle: "preetsuthar17", name: "Preet Suthar" },
  { handle: "emilkowalski", name: "Emil Kowalski" },
  { handle: "rauchg", name: "Guillermo Rauch" },
  { handle: "leerob", name: "Lee Robinson" },
]

export function ItemPeople() {
  return (
    <ItemGroup variant="grouped" className="max-w-sm">
      {people.map((person) => (
        <Item key={person.handle} size="sm">
          <ItemMedia>
            <Avatar size="lg">
              <AvatarImage
                src={`https://github.com/${person.handle}.png`}
                alt=""
              />
              <AvatarFallback>
                {person.name
                  .split(" ")
                  .map((part) => part[0])
                  .join("")}
              </AvatarFallback>
            </Avatar>
          </ItemMedia>
          <ItemContent>
            <ItemTitle>{person.name}</ItemTitle>
            <ItemDescription>@{person.handle}</ItemDescription>
          </ItemContent>
          <ItemActions>
            <Button
              variant="ghost"
              size="icon-sm"

              aria-label={`Invite ${person.name}`}
            >
              <IconPlus />
            </Button>
          </ItemActions>
        </Item>
      ))}
    </ItemGroup>
  )
}

Eylemler

<ItemActions /> düğmeleri satırın sonunda tutar. Öğe düğmeler içerdiğinde öğenin kendisini statik tutun; böylece bir bağlantının içinde asla düğme olmaz.

import { Avatar, AvatarFallback } from "@/components/ui/avatar"
import { Button } from "@/components/ui/button"
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemGroup,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item"

const invites = [
  { initials: "MO", name: "Mira Okafor", email: "[email protected]" },
  { initials: "JP", name: "Jun Park", email: "[email protected]" },
]

export function ItemActionsDemo() {
  return (
    <ItemGroup variant="grouped" className="max-w-md">
      {invites.map((invite) => (
        <Item key={invite.email} size="sm">
          <ItemMedia>
            <Avatar>
              <AvatarFallback>{invite.initials}</AvatarFallback>
            </Avatar>
          </ItemMedia>
          <ItemContent>
            <ItemTitle>{invite.name}</ItemTitle>
            <ItemDescription>{invite.email}</ItemDescription>
          </ItemContent>
          <ItemActions>
            <Button variant="ghost" size="sm">
              Decline
            </Button>
            <Button variant="outline" size="sm">
              Accept
            </Button>
          </ItemActions>
        </Item>
      ))}
    </ItemGroup>
  )
}

<ItemHeader /> ve <ItemFooter /> içeriğin üstünde ve altında tam bir satır kaplar.

import { Badge } from "@/components/ui/badge"
import {
  Item,
  ItemContent,
  ItemDescription,
  ItemFooter,
  ItemHeader,
  ItemTitle,
} from "@/components/ui/item"

export function ItemHeaderFooter() {
  return (
    <Item variant="outline" className="max-w-sm" render={<a href="#" />}>
      <ItemHeader>
        <span className="text-xs text-muted-foreground">hextaui/hextaui</span>
        <Badge>Open</Badge>
      </ItemHeader>
      <ItemContent>
        <ItemTitle>Rework the item component</ItemTitle>
        <ItemDescription>
          Grouped surfaces, a gliding hover highlight and selectable rows.
        </ItemDescription>
      </ItemContent>
      <ItemFooter>
        <span className="text-xs text-muted-foreground">
          #482 · 3 reviewers
        </span>
        <span className="text-xs text-muted-foreground">2h ago</span>
      </ItemFooter>
    </Item>
  )
}

Separator

Varsayılan bir grupta öğeler arasına kendiniz bir <ItemSeparator /> koyun.

import {
  Item,
  ItemContent,
  ItemDescription,
  ItemGroup,
  ItemSeparator,
  ItemTitle,
} from "@/components/ui/item"

export function ItemSeparatorDemo() {
  return (
    <ItemGroup className="max-w-sm">
      <Item size="sm">
        <ItemContent>
          <ItemTitle>Storage</ItemTitle>
          <ItemDescription>18.2 GB of 50 GB used</ItemDescription>
        </ItemContent>
      </Item>
      <ItemSeparator />
      <Item size="sm">
        <ItemContent>
          <ItemTitle>Bandwidth</ItemTitle>
          <ItemDescription>312 GB this month</ItemDescription>
        </ItemContent>
      </Item>
    </ItemGroup>
  )
}

Uzun içerik

Başlıklar bir satıra, açıklamalar iki satıra kısaltılır. Bölünmeyen dizeler satırı genişletmek yerine alt satıra sarar.

import { IconFile } from "@tabler/icons-react"

import { Button } from "@/components/ui/button"
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item"

export function ItemLongContent() {
  return (
    <Item variant="outline" className="max-w-sm">
      <ItemMedia variant="icon">
        <IconFile />
      </ItemMedia>
      <ItemContent>
        <ItemTitle>
          final-final-v3-approved-by-legal-and-design-do-not-edit-this-copy.pdf
        </ItemTitle>
        <ItemDescription>
          Uploaded to /projects/2026/client-work/very-long-folder-names/archive
          by [email protected] and shared with
          the whole organisation.
        </ItemDescription>
      </ItemContent>
      <ItemActions>
        <Button variant="outline" size="sm">
          Share
        </Button>
      </ItemActions>
    </Item>
  )
}

Sağdan sola

Dolgu, ayırıcı girintileri ve ok işareti okuma yönünü izler.

import { IconBell, IconUserCircle } from "@tabler/icons-react"

import {
  Item,
  ItemChevron,
  ItemContent,
  ItemDescription,
  ItemGroup,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item"

export function ItemRtl() {
  return (
    <div dir="rtl" className="w-full max-w-sm">
      <ItemGroup variant="grouped">
        <Item size="sm" render={<a href="#" />}>
          <ItemMedia variant="icon">
            <IconUserCircle />
          </ItemMedia>
          <ItemContent>
            <ItemTitle>الملف الشخصي</ItemTitle>
            <ItemDescription>الاسم والصورة</ItemDescription>
          </ItemContent>
          <ItemChevron />
        </Item>
        <Item size="sm" render={<a href="#" />}>
          <ItemMedia variant="icon">
            <IconBell />
          </ItemMedia>
          <ItemContent>
            <ItemTitle>الإشعارات</ItemTitle>
            <ItemDescription>الإشارات والردود</ItemDescription>
          </ItemContent>
          <ItemChevron />
        </Item>
      </ItemGroup>
    </div>
  )
}
TuşAction
TabSonraki etkileşimli öğeye, herhangi bir bağlantı veya düğme gibi kaynak sırasıyla geçer.
EnterBağlantı öğesini izler veya düğme öğesine basar.
SpaceDüğme öğesine basar veya etiket öğesini açıp kapatır.
  • Öğeleri düz satırlarsa grup bir listedir. Bağlantı veya düğme olarak render edilen öğeler kendi rollerini korur ve işaretleme geçerli kalsın diye grup liste rolünü bırakır. İkisini de istiyorsanız grubu <ul>, öğeleri bağlantıları saran <li> olarak render edin.
  • <ItemMedia variant="icon" /> ve ok ekran okuyuculardan gizlenir. Anlam taşıyan görsellere gerçek alt metni verin.
  • Vurgu yalnızca dekorasyondur. Klavye odağı odak halkasını gösterir; vurgu odağı hiçbir zaman taşımaz ve sekme sırasını değiştirmez.

Her parça varsayılan olarak bir <div> render eder ve render ile öğesinin niteliklerini kabul eder.

PropTürVarsayılan
variant
"default" | "outline" | "muted""default"
size
"default" | "sm" | "xs""default"
render
ReactElement | (props, state) => ReactElement<div>
ÖznitelikAçıklama
data-slot="item"CSS'te öğeleri hedefleyin.
data-variantGeçerli varyant.
data-sizeGeçerli boyut.
data-interactiveÖğe bağlantı, düğme veya etiket olarak işlendiğinde bulunur.
data-highlightedGrup vurgusu üzerindeyken bulunur.
--item-radiusKöşe yarıçapı. Medya köşeleri bundan türetilir. Boyuta göre ayarlanır.
--item-px / --item-py / --item-gapDolgu ve boşluk. Boyuta göre ayarlanır.
--item-media-sizeSimge ve görsel medyanın boyutu. size ile belirlenir.
--item-insetGruplanmış ayırıcının başladığı yer. Medya ne olursa olsun ItemContent ile hizalanacak şekilde ölçülür.
PropTürVarsayılan
variantgrouped, öğeleri otomatik ayırıcılarla tek bir yüzeye yerleştirir.
"default" | "grouped""default"
highlightHover sırasında etkileşimli öğeler arasında kayan tek bir vurgu gösterir.
booleantrue
render
ReactElement | (props, state) => ReactElement<div>
ÖznitelikAçıklama
data-slot="item-group"CSS'te grupları hedefleyin.
data-variantGeçerli varyant.
data-highlightHover vurgusu açıkken bulunur.
--item-group-radiusGruplanmış yüzeyin köşe yarıçapı. İlk ve son öğeler onu izler.
data-slot="item-highlight"Vurgu öğesi; data-visible ve data-pressed ile birlikte gelir.
PropTürVarsayılan
varianticon, simgeyi bir kutucuğa koyar ve ekran okuyuculardan gizler. image kareye kırpar. İkisinin de köşeleri öğeyle eş merkezlidir.
"default" | "icon" | "image""default"
toneicon varyantıyla kutucuğu düz bir renkle doldurur ve simgeyi iOS Ayarlar'daki gibi beyaza çevirir. Nötr bir kutucuk için ayarlamayın.
"gray" | "red" | "orange" | "yellow" | "green" | "teal" | "sky" | "blue" | "indigo" | "purple" | "pink"–
render
ReactElement | (props, state) => ReactElement<div>
ÖznitelikAçıklama
data-slot="item-media"CSS'te medyayı hedefler.
data-variantGeçerli varyant.
data-toneBir simgede tone ayarlandığında kutucuk rengi.
--item-media-toneKutucuk rengi. Özel bir ton için herhangi bir renk verin.
ÖznitelikAçıklama
data-slot="item-content"Satırı dolduracak şekilde büyür. İkinci bir içerik bloğu metnine sarılır.
ÖznitelikAçıklama
data-slot="item-title"Bir satırla sınırlı.
PropTürVarsayılan
render
ReactElement | (props, state) => ReactElement<p>
ÖznitelikAçıklama
data-slot="item-description"İki satırla sınırlı.
ÖznitelikAçıklama
data-slot="item-actions"CSS'te eylemleri hedefleyin.
ÖznitelikAçıklama
data-slot="item-header"İçeriğin üstünde tam genişlikte bir satır.
data-slot="item-footer"İçeriğin altında tam genişlikte bir satır.

Öğenin üzerine gelindiğinde okuma yönüne doğru hafifçe kayan bir son ok. Her Tabler simge prop'unu kabul eder.

ÖznitelikAçıklama
data-slot="item-chevron"CSS'te ok işaretini hedefler.
ÖznitelikAçıklama
data-slot="item-separator"role="separator" olan ince bir çizgi.