Arrange media, a title, supporting text, and actions in one row. Stack items with ItemGroup to build a list.
A simple item with title and description.
import { Button } from "@/components/ui/button"import { Item, ItemActions, ItemContent, ItemDescription, ItemMedia, ItemTitle,} from "@/components/ui/item"function BadgeCheckIcon(props: React.SVGProps<SVGSVGElement>) { return ( <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" {...props}> <path d="M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z" /> <path d="m9 12 2 2 4-4" /> </svg> )}function ChevronRightIcon(props: React.SVGProps<SVGSVGElement>) { return ( <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" {...props}> <path d="m9 18 6-6-6-6" /> </svg> )}export function Example() { return ( <div className="flex w-full max-w-md flex-col gap-4"> <Item variant="outline"> <ItemContent> <ItemTitle>Basic Item</ItemTitle> <ItemDescription> A simple item with title and description. </ItemDescription> </ItemContent> <ItemActions> <Button variant="outline" size="sm"> Action </Button> </ItemActions> </Item> <Item variant="outline" size="sm" render={<a href="#" />}> <ItemMedia> <BadgeCheckIcon className="size-5" /> </ItemMedia> <ItemContent> <ItemTitle>Your profile has been verified.</ItemTitle> </ItemContent> <ItemActions> <ChevronRightIcon className="size-4" /> </ItemActions> </Item> </div> )}Installation
npx @arctis-sh/@arctis-sh/ui@latest add itemUsage
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>Composition
ItemGroup
└── Item
├── ItemHeader
├── ItemMedia
├── ItemContent
│ ├── ItemTitle
│ └── ItemDescription
├── ItemActions
└── ItemFooterVariant
Use variant to choose a default, outlined, or muted surface.
Transparent background with no border.
Outlined style with a visible border.
Muted background for secondary content.
import { Item, ItemContent, ItemDescription, ItemTitle,} from "@/components/ui/item"export function Example() { return ( <div className="flex w-full max-w-md flex-col gap-4"> <Item> <ItemContent> <ItemTitle>Default</ItemTitle> <ItemDescription> Transparent background with no border. </ItemDescription> </ItemContent> </Item> <Item variant="outline"> <ItemContent> <ItemTitle>Outline</ItemTitle> <ItemDescription>Outlined style with a visible border.</ItemDescription> </ItemContent> </Item> <Item variant="muted"> <ItemContent> <ItemTitle>Muted</ItemTitle> <ItemDescription> Muted background for secondary content. </ItemDescription> </ItemContent> </Item> </div> )}Size
size accepts default, sm, or xs.
The standard size for most use cases.
A compact size for dense layouts.
The most compact size available.
import { Item, ItemContent, ItemDescription, ItemMedia, ItemTitle,} from "@/components/ui/item"function InboxIcon(props: React.SVGProps<SVGSVGElement>) { return ( <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" {...props}> <polyline points="22 12 16 12 14 15 10 15 8 12 2 12" /> <path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" /> </svg> )}export function Example() { return ( <div className="flex w-full max-w-md flex-col gap-4"> <Item variant="outline"> <ItemMedia variant="icon"> <InboxIcon /> </ItemMedia> <ItemContent> <ItemTitle>Default</ItemTitle> <ItemDescription>The standard size for most use cases.</ItemDescription> </ItemContent> </Item> <Item variant="outline" size="sm"> <ItemMedia variant="icon"> <InboxIcon /> </ItemMedia> <ItemContent> <ItemTitle>Small</ItemTitle> <ItemDescription>A compact size for dense layouts.</ItemDescription> </ItemContent> </Item> <Item variant="outline" size="xs"> <ItemMedia variant="icon"> <InboxIcon /> </ItemMedia> <ItemContent> <ItemTitle>Extra small</ItemTitle> <ItemDescription>The most compact size available.</ItemDescription> </ItemContent> </Item> </div> )}Icon
Set variant="icon" on ItemMedia for an icon tile.
New login detected from unknown device.
import { Button } from "@/components/ui/button"import { Item, ItemActions, ItemContent, ItemDescription, ItemMedia, ItemTitle,} from "@/components/ui/item"function ShieldAlertIcon(props: React.SVGProps<SVGSVGElement>) { return ( <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" {...props}> <path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z" /> <path d="M12 8v4" /> <path d="M12 16h.01" /> </svg> )}export function Example() { return ( <Item variant="outline" className="max-w-lg"> <ItemMedia variant="icon"> <ShieldAlertIcon /> </ItemMedia> <ItemContent> <ItemTitle>Security Alert</ItemTitle> <ItemDescription> New login detected from unknown device. </ItemDescription> </ItemContent> <ItemActions> <Button size="sm" variant="outline"> Review </Button> </ItemActions> </Item> )}Avatar
Place an Avatar inside ItemMedia.
Last seen 5 months ago
Invite people to this project.
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"import { Button } from "@/components/ui/button"import { Item, ItemActions, ItemContent, ItemDescription, ItemMedia, ItemTitle,} from "@/components/ui/item"export function Example() { return ( <div className="flex w-full max-w-lg flex-col gap-4"> <Item variant="outline"> <ItemMedia> <Avatar size="sm"> <AvatarImage src="/assets/brand/demos/avatars/avatar-1.png" alt="Mina Cho" /> <AvatarFallback>MC</AvatarFallback> </Avatar> </ItemMedia> <ItemContent> <ItemTitle>Mina Cho</ItemTitle> <ItemDescription>Last seen 5 months ago</ItemDescription> </ItemContent> </Item> <Item variant="outline"> <ItemMedia> <div className="flex -space-x-2"> <Avatar size="sm" className="ring-2 ring-background"> <AvatarImage src="/assets/brand/demos/avatars/avatar-2.png" alt="Jonas Berg" /> <AvatarFallback>JB</AvatarFallback> </Avatar> <Avatar size="sm" className="ring-2 ring-background"> <AvatarImage src="/assets/brand/demos/avatars/avatar-3.png" alt="Elsa Lind" /> <AvatarFallback>EL</AvatarFallback> </Avatar> <Avatar size="sm" className="ring-2 ring-background"> <AvatarImage src="/assets/brand/demos/avatars/avatar-4.png" alt="Noah Park" /> <AvatarFallback>NP</AvatarFallback> </Avatar> </div> </ItemMedia> <ItemContent> <ItemTitle>No members</ItemTitle> <ItemDescription>Invite people to this project.</ItemDescription> </ItemContent> <ItemActions> <Button size="sm" variant="outline"> Invite </Button> </ItemActions> </Item> </div> )}Image
Set variant="image" on ItemMedia for cover art or thumbnails.

Electric Nights

Urban Stories

Binary Beats
import { Item, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemTitle,} from "@/components/ui/item"const tracks = [ { title: "Midnight City Lights", description: "Electric Nights", image: "/assets/brand/demos/attachments/attachment-1.png", duration: "3:45", }, { title: "Coffee Shop Conversations", description: "Urban Stories", image: "/assets/brand/demos/attachments/attachment-2.png", duration: "4:05", }, { title: "Digital Rain", description: "Binary Beats", image: "/assets/brand/demos/attachments/attachment-3.png", duration: "3:30", },] as constexport function Example() { return ( <ItemGroup className="max-w-md gap-4"> {tracks.map((track) => ( <Item key={track.title} variant="outline"> <ItemMedia variant="image"> <img src={track.image} alt={track.title} /> </ItemMedia> <ItemContent> <div className="flex items-center justify-between gap-2"> <ItemTitle>{track.title}</ItemTitle> <span className="shrink-0 text-sm text-muted-foreground"> {track.duration} </span> </div> <ItemDescription>{track.description}</ItemDescription> </ItemContent> </Item> ))} </ItemGroup> )}Group
Group related rows with ItemGroup and, when needed, ItemSeparator.
mina@arctis.dev
jonas@arctis.dev
elsa@arctis.dev
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"import { Item, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemSeparator, ItemTitle,} from "@/components/ui/item"const people = [ { name: "Mina Cho", email: "mina@arctis.dev", src: "/assets/brand/demos/avatars/avatar-1.png", fallback: "MC", }, { name: "Jonas Berg", email: "jonas@arctis.dev", src: "/assets/brand/demos/avatars/avatar-2.png", fallback: "JB", }, { name: "Elsa Lind", email: "elsa@arctis.dev", src: "/assets/brand/demos/avatars/avatar-3.png", fallback: "EL", },] as constexport function Example() { return ( <ItemGroup className="max-w-md rounded-md border border-border"> {people.map((person, index) => ( <div key={person.email}> {index > 0 ? <ItemSeparator /> : null} <Item> <ItemMedia> <Avatar size="sm"> <AvatarImage src={person.src} alt={person.name} /> <AvatarFallback>{person.fallback}</AvatarFallback> </Avatar> </ItemMedia> <ItemContent> <ItemTitle>{person.name}</ItemTitle> <ItemDescription>{person.email}</ItemDescription> </ItemContent> </Item> </div> ))} </ItemGroup> )}Header
Add ItemHeader above the content for card-style layouts.

Everyday tasks and UI generation.

Advanced thinking or reasoning.

Open source model for everyone.
import { Item, ItemContent, ItemDescription, ItemHeader, ItemTitle,} from "@/components/ui/item"const models = [ { name: "v0-1.5-sm", description: "Everyday tasks and UI generation.", image: "/assets/brand/demos/attachments/attachment-1.png", }, { name: "v0-1.5-lg", description: "Advanced thinking or reasoning.", image: "/assets/brand/demos/attachments/attachment-2.png", }, { name: "v0-2.0-mini", description: "Open source model for everyone.", image: "/assets/brand/demos/attachments/attachment-3.png", },] as constexport function Example() { return ( <div className="grid w-full max-w-2xl gap-4 sm:grid-cols-3"> {models.map((model) => ( <Item key={model.name} variant="outline" className="flex-col flex-nowrap items-stretch gap-3" > <ItemHeader className="block"> <img src={model.image} alt={model.name} className="aspect-[4/3] w-full rounded-sm object-cover" /> </ItemHeader> <ItemContent className="w-full flex-none"> <ItemTitle>{model.name}</ItemTitle> <ItemDescription>{model.description}</ItemDescription> </ItemContent> </Item> ))} </div> )}Link
Pass render to make the item a real <a> or <button>.
import { Item, ItemActions, ItemContent, ItemDescription, ItemTitle,} from "@/components/ui/item"function ChevronRightIcon(props: React.SVGProps<SVGSVGElement>) { return ( <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" {...props}> <path d="m9 18 6-6-6-6" /> </svg> )}function ExternalLinkIcon(props: React.SVGProps<SVGSVGElement>) { return ( <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true" {...props}> <path d="M15 3h6v6" /> <path d="M10 14 21 3" /> <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" /> </svg> )}export function Example() { return ( <div className="flex w-full max-w-md flex-col gap-3"> <Item render={<a href="#" />}> <ItemContent> <ItemTitle>Visit our documentation</ItemTitle> <ItemDescription> Learn how to get started with our components. </ItemDescription> </ItemContent> <ItemActions> <ChevronRightIcon className="size-4" /> </ItemActions> </Item> <Item variant="outline" render={<a href="https://example.com" target="_blank" rel="noreferrer noopener" />} > <ItemContent> <ItemTitle>External resource</ItemTitle> <ItemDescription> Opens in a new tab with security attributes. </ItemDescription> </ItemContent> <ItemActions> <ExternalLinkIcon className="size-4" /> </ItemActions> </Item> </div> )}<Item render={<a href="/dashboard" />}> <ItemContent> <ItemTitle>Dashboard</ItemTitle> <ItemDescription>Overview of your account and activity.</ItemDescription> </ItemContent></Item>API Reference
Item
Root row. itemVariants is also exported for composing styles. Standard HTML attributes pass through to the root or the element provided through render.
| Prop | Type | Default |
|---|---|---|
| variant | "default" | "outline" | "muted" | "default" |
| size | "default" | "sm" | "xs" | "default" |
| render | ReactElement | — |
| className | string | — |
<Item variant="outline" size="sm"> <ItemContent> <ItemTitle>Title</ItemTitle> </ItemContent></Item>ItemGroup
Groups related items. Renders with role="list".
<ItemGroup> <Item /> <Item /></ItemGroup>ItemSeparator
Separator between items in a group.
<ItemGroup> <Item /> <ItemSeparator /> <Item /></ItemGroup>ItemMedia
Media slot for icons, images, or avatars.
| Prop | Type | Default |
|---|---|---|
| variant | "default" | "icon" | "image" | "default" |
| className | string | — |
<ItemMedia variant="icon"> <Icon /></ItemMedia><ItemMedia variant="image"> <img src="..." alt="..." /></ItemMedia>ItemContent
Wraps the title and description.
<ItemContent> <ItemTitle>Title</ItemTitle> <ItemDescription>Description</ItemDescription></ItemContent>ItemTitle
Primary label for the item.
<ItemTitle>Item Title</ItemTitle>ItemDescription
Supporting text. Clamps to two lines.
<ItemDescription>Item description</ItemDescription>ItemActions
Container for buttons or other actions.
<ItemActions> <Button>Action</Button></ItemActions>ItemHeader
Full-width header above the content.
<Item> <ItemHeader>Header</ItemHeader> <ItemContent>...</ItemContent></Item>ItemFooter
Full-width footer below the content.
<Item> <ItemContent>...</ItemContent> <ItemFooter>Footer</ItemFooter></Item>