List item layout primitives for rich rows
Basic Item
A simple item with title and description.
Your profile has been verified.
import { Button } from '@/components/ui/button'
import { Item, ItemActions, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemTitle } from '@/components/ui/item'
...import { Button } from '@/components/ui/button'
import { Item, ItemActions, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemTitle } from '@/components/ui/item'
export default function ItemDemoExample() {
return (
<ItemGroup class="w-md"><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" asChild><a href="#"><ItemMedia>✓</ItemMedia><ItemContent><ItemTitle>Your profile has been verified.</ItemTitle></ItemContent><ItemActions>›</ItemActions></a></Item></ItemGroup>
)
}
Installation
npx @fictjs/shadcn@latest add itemCopy the Fict shadcn component into your project.
Source
components/ui/item.tsx
src/components/ui/item.tsx
import { Slot } from '@fictjs/radix-ui'
import { cn } from '@/lib/cn'
type DivProps = JSX.IntrinsicElements['div']
type HeadingProps = JSX.IntrinsicElements['h4']
type ParagraphProps = JSX.IntrinsicElements['p']
type ItemProps = DivProps & {
variant?: 'default' | 'outline' | 'muted'
size?: 'default' | 'sm' | 'xs'
asChild?: boolean
}
export function Item(props: ItemProps) {
const { class: className, variant = 'default', size = 'default', asChild, ...rest } = props
const classValue = cn(
'flex items-start gap-3 rounded-lg',
variant === 'outline' && 'border',
variant === 'muted' && 'bg-muted',
size === 'default' && 'p-4',
size === 'sm' && 'p-3',
size === 'xs' && 'gap-2 p-2',
className,
)
if (asChild) return <Slot.Root data-slot='item' data-variant={variant} data-size={size} class={classValue} {...rest} />
return <div data-slot='item' data-variant={variant} data-size={size} class={classValue} {...rest} />
}
export function ItemLeading(props: DivProps) {
const { class: className, ...rest } = props
return <div data-slot='item-media' class={cn('mt-0.5 shrink-0 text-muted-foreground', className)} {...rest} />
}
export const ItemMedia = ItemLeading
export function ItemContent(props: DivProps) {
const { class: className, ...rest } = props
return <div data-slot='item-content' class={cn('grid min-w-0 gap-1', className)} {...rest} />
}
export function ItemTitle(props: HeadingProps) {
const { class: className, ...rest } = props
return <h4 data-slot='item-title' class={cn('truncate text-sm font-medium', className)} {...rest} />
}
export function ItemDescription(props: ParagraphProps) {
const { class: className, ...rest } = props
return <p data-slot='item-description' class={cn('text-sm text-muted-foreground', className)} {...rest} />
}
export function ItemTrailing(props: DivProps) {
const { class: className, ...rest } = props
return <div data-slot='item-actions' class={cn('ml-auto shrink-0', className)} {...rest} />
}
export const ItemActions = ItemTrailing
export function ItemGroup(props: DivProps) {
const { class: className, ...rest } = props
return <div data-slot='item-group' class={cn('grid gap-2', className)} {...rest} />
}
export function ItemHeader(props: DivProps) {
const { class: className, ...rest } = props
return <div data-slot='item-header' class={cn('overflow-hidden rounded-t-lg', className)} {...rest} />
}
Usage
Examples
Variant
Default Variant
Transparent background with no border.
Outline Variant
Outlined style with a visible border.
Muted Variant
Muted background for secondary content.
import { Item, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemTitle } from '@/components/ui/item'
...import { Item, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemTitle } from '@/components/ui/item'
const variants = [['default', 'Default Variant', 'Transparent background with no border.'], ['outline', 'Outline Variant', 'Outlined style with a visible border.'], ['muted', 'Muted Variant', 'Muted background for secondary content.']] as const
export default function ItemVariantExample() {
return (
<ItemGroup class="w-md">{variants.map(([variant, title, description]) => <Item variant={variant}><ItemMedia>▣</ItemMedia><ItemContent><ItemTitle>{title}</ItemTitle><ItemDescription>{description}</ItemDescription></ItemContent></Item>)}</ItemGroup>
)
}
Size
Default Size
The standard size for most use cases.
Small Size
A compact size for dense layouts.
Extra Small Size
The most compact size available.
import { Item, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemTitle } from '@/components/ui/item'
...import { Item, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemTitle } from '@/components/ui/item'
const sizes = [['default', 'Default Size', 'The standard size for most use cases.'], ['sm', 'Small Size', 'A compact size for dense layouts.'], ['xs', 'Extra Small Size', 'The most compact size available.']] as const
export default function ItemSizeExample() {
return (
<ItemGroup class="w-md">{sizes.map(([size, title, description]) => <Item variant="outline" size={size}><ItemMedia>▣</ItemMedia><ItemContent><ItemTitle>{title}</ItemTitle><ItemDescription>{description}</ItemDescription></ItemContent></Item>)}</ItemGroup>
)
}
Icon
Security Alert
New login detected from unknown device.
import { Button } from '@/components/ui/button'
import { Item, ItemActions, ItemContent, ItemDescription, ItemMedia, ItemTitle } from '@/components/ui/item'
...import { Button } from '@/components/ui/button'
import { Item, ItemActions, ItemContent, ItemDescription, ItemMedia, ItemTitle } from '@/components/ui/item'
export default function ItemIconExample() {
return (
<Item variant="outline" class="w-lg"><ItemMedia class="rounded-md bg-muted p-2">♢</ItemMedia><ItemContent><ItemTitle>Security Alert</ItemTitle><ItemDescription>New login detected from unknown device.</ItemDescription></ItemContent><ItemActions><Button variant="outline" size="sm">Review</Button></ItemActions></Item>
)
}
Avatar

Evil Rabbit
Last seen 5 months ago



No Team Members
Invite your team to collaborate on this project.
import { Avatar, AvatarFallback, AvatarGroup, AvatarImage } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
...import { Avatar, AvatarFallback, AvatarGroup, AvatarImage } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
import { Item, ItemActions, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemTitle } from '@/components/ui/item'
export default function ItemAvatarExample() {
return (
<ItemGroup class="w-lg"><Item variant="outline"><ItemMedia><Avatar size="lg"><AvatarImage src="https://github.com/evilrabbit.png" alt="Evil Rabbit" /><AvatarFallback>ER</AvatarFallback></Avatar></ItemMedia><ItemContent><ItemTitle>Evil Rabbit</ItemTitle><ItemDescription>Last seen 5 months ago</ItemDescription></ItemContent><ItemActions><Button variant="outline" size="icon-sm" aria-label="Invite">+</Button></ItemActions></Item><Item variant="outline"><ItemMedia><AvatarGroup><Avatar><AvatarImage src="https://github.com/shadcn.png" alt="shadcn" /></Avatar><Avatar><AvatarImage src="https://github.com/maxleiter.png" alt="maxleiter" /></Avatar><Avatar><AvatarImage src="https://github.com/evilrabbit.png" alt="evilrabbit" /></Avatar></AvatarGroup></ItemMedia><ItemContent><ItemTitle>No Team Members</ItemTitle><ItemDescription>Invite your team to collaborate on this project.</ItemDescription></ItemContent><ItemActions><Button variant="outline" size="sm">Invite</Button></ItemActions></Item></ItemGroup>
)
}
Image
import { Item, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemTitle } from '@/components/ui/item'
...import { Item, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemTitle } from '@/components/ui/item'
const songs = [['Midnight City Lights', 'Electric Nights', 'Neon Dreams', '3:45'], ['Coffee Shop Conversations', 'Urban Stories', 'The Morning Brew', '4:05'], ['Digital Rain', 'Binary Beats', 'Cyber Symphony', '3:30']] as const
export default function ItemImageExample() {
return (
<ItemGroup class="w-md">{songs.map(([title, artist, album, duration]) => <Item variant="outline" asChild><a href="#"><ItemMedia><img class="size-10 rounded-sm object-cover" src={`https://avatar.vercel.sh/${encodeURIComponent(title)}`} alt={title} /></ItemMedia><ItemContent><ItemTitle>{title} - <span>{artist}</span></ItemTitle><ItemDescription>{album}</ItemDescription></ItemContent><ItemContent class="max-w-10"><ItemDescription>{duration}</ItemDescription></ItemContent></a></Item>)}</ItemGroup>
)
}
Group

shadcn
shadcn@vercel.com

maxleiter
maxleiter@vercel.com

evilrabbit
evilrabbit@vercel.com
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
...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 = [['shadcn', 'shadcn@vercel.com'], ['maxleiter', 'maxleiter@vercel.com'], ['evilrabbit', 'evilrabbit@vercel.com']] as const
export default function ItemGroupExample() {
return (
<ItemGroup class="w-96">{people.map(([name, email]) => <Item variant="outline"><ItemMedia><Avatar><AvatarImage src={`https://github.com/${name}.png`} alt={name} /><AvatarFallback>{name.slice(0, 2)}</AvatarFallback></Avatar></ItemMedia><ItemContent><ItemTitle>{name}</ItemTitle><ItemDescription>{email}</ItemDescription></ItemContent><ItemActions><Button variant="ghost" size="icon" aria-label={`Add ${name}`}>+</Button></ItemActions></Item>)}</ItemGroup>
)
}
Header
v0-1.5-sm
Everyday tasks and UI generation.
v0-1.5-lg
Advanced thinking or reasoning.
v0-2.0-mini
Open Source model for everyone.
import { Item, ItemContent, ItemDescription, ItemHeader, ItemTitle } from '@/components/ui/item'
...import { Item, ItemContent, ItemDescription, ItemHeader, ItemTitle } from '@/components/ui/item'
const models = [['v0-1.5-sm', 'Everyday tasks and UI generation.', 'https://images.unsplash.com/photo-1650804068570-7fb2e3dbf888?q=80&w=640&auto=format&fit=crop'], ['v0-1.5-lg', 'Advanced thinking or reasoning.', 'https://images.unsplash.com/photo-1610280777472-54133d004c8c?q=80&w=640&auto=format&fit=crop'], ['v0-2.0-mini', 'Open Source model for everyone.', 'https://images.unsplash.com/photo-1602146057681-08560aee8cde?q=80&w=640&auto=format&fit=crop']] as const
export default function ItemHeaderExample() {
return (
<div class="grid grid-cols-3 gap-3">{models.map(([name, description, image]) => <Item variant="outline" class="block p-0"><ItemHeader><img class="aspect-video w-full object-cover" src={image} alt={name} /></ItemHeader><ItemContent class="p-4"><ItemTitle>{name}</ItemTitle><ItemDescription>{description}</ItemDescription></ItemContent></Item>)}</div>
)
}
Link
import { Item, ItemActions, ItemContent, ItemDescription, ItemGroup, ItemTitle } from '@/components/ui/item'
...import { Item, ItemActions, ItemContent, ItemDescription, ItemGroup, ItemTitle } from '@/components/ui/item'
export default function ItemLinkExample() {
return (
<ItemGroup class="w-md"><Item asChild><a href="#"><ItemContent><ItemTitle>Visit our documentation</ItemTitle><ItemDescription>Learn how to get started with our components.</ItemDescription></ItemContent><ItemActions>›</ItemActions></a></Item><Item variant="outline" asChild><a href="#" target="_blank" rel="noopener noreferrer"><ItemContent><ItemTitle>External resource</ItemTitle><ItemDescription>Opens in a new tab with security attributes.</ItemDescription></ItemContent><ItemActions>↗</ItemActions></a></Item></ItemGroup>
)
}
Dropdown
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
...import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'
import { Item, ItemContent, ItemDescription, ItemMedia, ItemTitle } from '@/components/ui/item'
const people = [['shadcn', 'shadcn@vercel.com'], ['maxleiter', 'maxleiter@vercel.com'], ['evilrabbit', 'evilrabbit@vercel.com']] as const
export default function ItemDropdownExample() {
return (
<DropdownMenu><DropdownMenuTrigger asChild><Button variant="outline">Select⌄</Button></DropdownMenuTrigger><DropdownMenuContent align="end">{people.map(([name, email]) => <DropdownMenuItem><Item size="xs"><ItemMedia><Avatar><AvatarImage src={`https://github.com/${name}.png`} alt={name} /><AvatarFallback>{name.slice(0, 2)}</AvatarFallback></Avatar></ItemMedia><ItemContent><ItemTitle>{name}</ItemTitle><ItemDescription>{email}</ItemDescription></ItemContent></Item></DropdownMenuItem>)}</DropdownMenuContent></DropdownMenu>
)
}
Rtl
import { Button } from '@/components/ui/button'
import { Item, ItemActions, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemTitle } from '@/components/ui/item'
...import { Button } from '@/components/ui/button'
import { Item, ItemActions, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemTitle } from '@/components/ui/item'
const translations = {
ar: { dir: 'rtl', basic: 'عنصر أساسي', description: 'عنصر بسيط يحتوي على عنوان ووصف.', action: 'إجراء', verified: 'تم التحقق من ملفك الشخصي.' },
he: { dir: 'rtl', basic: 'פריט בסיסי', description: 'פריט פשוט עם כותרת ותיאור.', action: 'פעולה', verified: 'הפרופיל שלך אומת.' },
en: { dir: 'ltr', basic: 'Basic Item', description: 'A simple item with title and description.', action: 'Action', verified: 'Your profile has been verified.' },
} as const
export default function ItemRtlExample() {
let language = $state<keyof typeof translations>('ar')
const t = translations[language]
return (
<div><select aria-label="Preview language" value={language} onChange={event => language = event.currentTarget.value as keyof typeof translations}><option value="ar">Arabic (العربية)</option><option value="he">Hebrew (עברית)</option><option value="en">English</option></select><ItemGroup class="w-md" dir={t.dir}><Item variant="outline"><ItemContent><ItemTitle>{t.basic}</ItemTitle><ItemDescription>{t.description}</ItemDescription></ItemContent><ItemActions><Button variant="outline" size="sm">{t.action}</Button></ItemActions></Item><Item variant="outline" size="sm" asChild><a href="#"><ItemMedia>✓</ItemMedia><ItemContent><ItemTitle>{t.verified}</ItemTitle></ItemContent><ItemActions>›</ItemActions></a></Item></ItemGroup></div>
)
}