8.0k New

Item

A versatile component for displaying content with media, title, description, and actions.

Epicenter

Local-first, open source apps

Special Sponsor
Basic Item

A simple item with title and description.

Your profile has been verified.
<script lang="ts">
	import BadgeCheckIcon from "@lucide/svelte/icons/badge-check";
	import ChevronRightIcon from "@lucide/svelte/icons/chevron-right";
	import * as Item from "$lib/components/ui/item/index.js";
	import { Button } from "$lib/components/ui/button/index.js";
</script>
 
<div class="flex w-full max-w-md flex-col gap-6">
	<Item.Root variant="outline">
		<Item.Content>
			<Item.Title>Basic Item</Item.Title>
			<Item.Description>A simple item with title and description.</Item.Description>
		</Item.Content>
		<Item.Actions>
			<Button variant="outline" size="sm">Action</Button>
		</Item.Actions>
	</Item.Root>
	<Item.Root variant="outline" size="sm">
		{#snippet child({ props })}
			<a href="##" {...props}>
				<Item.Media>
					<BadgeCheckIcon class="size-5" />
				</Item.Media>
				<Item.Content>
					<Item.Title>Your profile has been verified.</Item.Title>
				</Item.Content>
				<Item.Actions>
					<ChevronRightIcon class="size-4" />
				</Item.Actions>
			</a>
		{/snippet}
	</Item.Root>
</div>

The Item component is a straightforward flex container that can house nearly any type of content. Use it to display a title, description, and actions. Group it with the Item.Group component to create a list of items.

Installation

pnpm dlx shadcn-svelte@latest add item

Usage

<script lang="ts">
  import * as Item from "$lib/components/ui/item/index.js";
</script>
<Item.Root>
  <Item.Header>Item Header</Item.Header>
  <Item.Media />
  <Item.Content>
    <Item.Title>Item</Item.Title>
    <Item.Description>Item</Item.Description>
  </Item.Content>
  <Item.Actions />
  <Item.Footer>Item Footer</Item.Footer>
</Item.Root>

Item vs Field

Use Field if you need to display a form input such as a checkbox, input, radio, or select.

If you only need to display content such as a title, description, and actions, use Item.

Variant

Use the variant prop to change the visual style of the item.

Default Variant

Transparent background with no border.

Outline Variant

Outlined style with a visible border.

Muted Variant

Muted background for secondary content.

<script lang="ts">
	import InboxIcon from "@lucide/svelte/icons/inbox";
	import * as Item from "$lib/components/ui/item/index.js";
</script>
 
<div class="flex w-full max-w-md flex-col gap-6">
	<Item.Root>
		<Item.Media variant="icon">
			<InboxIcon />
		</Item.Media>
		<Item.Content>
			<Item.Title>Default Variant</Item.Title>
			<Item.Description>Transparent background with no border.</Item.Description>
		</Item.Content>
	</Item.Root>
	<Item.Root variant="outline">
		<Item.Media variant="icon">
			<InboxIcon />
		</Item.Media>
		<Item.Content>
			<Item.Title>Outline Variant</Item.Title>
			<Item.Description>Outlined style with a visible border.</Item.Description>
		</Item.Content>
	</Item.Root>
	<Item.Root variant="muted">
		<Item.Media variant="icon">
			<InboxIcon />
		</Item.Media>
		<Item.Content>
			<Item.Title>Muted Variant</Item.Title>
			<Item.Description>Muted background for secondary content.</Item.Description>
		</Item.Content>
	</Item.Root>
</div>

Size

Use the size prop to change the size of the item. Available sizes are default, sm, and xs.

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.

<script lang="ts">
	import InboxIcon from "@lucide/svelte/icons/inbox";
	import * as Item from "$lib/components/ui/item/index.js";
</script>
 
<div class="flex w-full max-w-md flex-col gap-6">
	<Item.Root variant="outline">
		<Item.Media variant="icon">
			<InboxIcon />
		</Item.Media>
		<Item.Content>
			<Item.Title>Default Size</Item.Title>
			<Item.Description>The standard size for most use cases.</Item.Description>
		</Item.Content>
	</Item.Root>
	<Item.Root variant="outline" size="sm">
		<Item.Media variant="icon">
			<InboxIcon />
		</Item.Media>
		<Item.Content>
			<Item.Title>Small Size</Item.Title>
			<Item.Description>A compact size for dense layouts.</Item.Description>
		</Item.Content>
	</Item.Root>
	<Item.Root variant="outline" size="xs">
		<Item.Media variant="icon">
			<InboxIcon />
		</Item.Media>
		<Item.Content>
			<Item.Title>Extra Small Size</Item.Title>
			<Item.Description>The most compact size available.</Item.Description>
		</Item.Content>
	</Item.Root>
</div>

Icon

Use Item.Media with variant="icon" to display an icon.

Security Alert

New login detected from unknown device.

<script lang="ts">
	import ShieldAlertIcon from "@lucide/svelte/icons/shield-alert";
	import * as Item from "$lib/components/ui/item/index.js";
	import { Button } from "$lib/components/ui/button/index.js";
</script>
 
<div class="flex w-full max-w-lg flex-col gap-6">
	<Item.Root variant="outline">
		<Item.Media variant="icon">
			<ShieldAlertIcon />
		</Item.Media>
		<Item.Content>
			<Item.Title>Security Alert</Item.Title>
			<Item.Description>New login detected from unknown device.</Item.Description>
		</Item.Content>
		<Item.Actions>
			<Button size="sm" variant="outline">Review</Button>
		</Item.Actions>
	</Item.Root>
</div>

Avatar

You can use Item.Media with variant="avatar" to display an avatar.

ER
Evil Rabbit

Last seen 5 months ago

ER
No Team Members

Invite your team to collaborate on this project.

<script lang="ts">
	import Plus from "@lucide/svelte/icons/plus";
	import * as Avatar from "$lib/components/ui/avatar/index.js";
	import * as Item from "$lib/components/ui/item/index.js";
	import { Button } from "$lib/components/ui/button/index.js";
</script>
 
<div class="flex w-full max-w-lg flex-col gap-6">
	<Item.Root variant="outline">
		<Item.Media>
			<Avatar.Root class="size-10">
				<Avatar.Image src="https://github.com/evilrabbit.png" />
				<Avatar.Fallback>ER</Avatar.Fallback>
			</Avatar.Root>
		</Item.Media>
		<Item.Content>
			<Item.Title>Evil Rabbit</Item.Title>
			<Item.Description>Last seen 5 months ago</Item.Description>
		</Item.Content>
		<Item.Actions>
			<Button size="icon-sm" variant="outline" class="rounded-full" aria-label="Invite">
				<Plus />
			</Button>
		</Item.Actions>
	</Item.Root>
	<Item.Root variant="outline">
		<Item.Media>
			<div
				class="flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background *:data-[slot=avatar]:grayscale"
			>
				<Avatar.Root class="hidden sm:flex">
					<Avatar.Image src="https://github.com/shadcn.png" alt="@shadcn" />
					<Avatar.Fallback>CN</Avatar.Fallback>
				</Avatar.Root>
				<Avatar.Root class="hidden sm:flex">
					<Avatar.Image src="https://github.com/maxleiter.png" alt="@maxleiter" />
					<Avatar.Fallback>LR</Avatar.Fallback>
				</Avatar.Root>
				<Avatar.Root>
					<Avatar.Image src="https://github.com/evilrabbit.png" alt="@evilrabbit" />
					<Avatar.Fallback>ER</Avatar.Fallback>
				</Avatar.Root>
			</div>
		</Item.Media>
		<Item.Content>
			<Item.Title>No Team Members</Item.Title>
			<Item.Description>Invite your team to collaborate on this project.</Item.Description>
		</Item.Content>
		<Item.Actions>
			<Button size="sm" variant="outline">Invite</Button>
		</Item.Actions>
	</Item.Root>
</div>

Image

Use Item.Media with variant="image" to display an image.

<script lang="ts">
	import * as Item from "$lib/components/ui/item/index.js";
 
	const music = [
		{
			title: "Midnight City Lights",
			artist: "Neon Dreams",
			album: "Electric Nights",
			duration: "3:45",
		},
		{
			title: "Coffee Shop Conversations",
			artist: "The Morning Brew",
			album: "Urban Stories",
			duration: "4:05",
		},
		{
			title: "Digital Rain",
			artist: "Cyber Symphony",
			album: "Binary Beats",
			duration: "3:30",
		},
	];
</script>
 
<div class="flex w-full max-w-md flex-col gap-6">
	<Item.Group class="gap-4">
		{#each music as song (song.title)}
			<Item.Root variant="outline" role="listitem">
				{#snippet child({ props })}
					<a href="##" {...props}>
						<Item.Media variant="image">
							<img
								src={`https://avatar.vercel.sh/${song.title}`}
								alt={song.title}
								width={32}
								height={32}
								class="object-cover grayscale"
							/>
						</Item.Media>
						<Item.Content>
							<Item.Title class="line-clamp-1">
								{song.title} -
								<span class="text-muted-foreground">{song.album}</span>
							</Item.Title>
							<Item.Description>{song.artist}</Item.Description>
						</Item.Content>
						<Item.Content class="flex-none text-center">
							<Item.Description>{song.duration}</Item.Description>
						</Item.Content>
					</a>
				{/snippet}
			</Item.Root>
		{/each}
	</Item.Group>
</div>

Group

Use Item.Group to group related items together.

s
shadcn

shadcn@vercel.com

m
maxleiter

maxleiter@vercel.com

e
evilrabbit

evilrabbit@vercel.com

<script lang="ts">
	import Plus from "@lucide/svelte/icons/plus";
	import * as Avatar from "$lib/components/ui/avatar/index.js";
	import * as Item from "$lib/components/ui/item/index.js";
	import { Button } from "$lib/components/ui/button/index.js";
 
	const people = [
		{
			username: "shadcn",
			avatar: "https://github.com/shadcn.png",
			email: "shadcn@vercel.com",
		},
		{
			username: "maxleiter",
			avatar: "https://github.com/maxleiter.png",
			email: "maxleiter@vercel.com",
		},
		{
			username: "evilrabbit",
			avatar: "https://github.com/evilrabbit.png",
			email: "evilrabbit@vercel.com",
		},
	];
</script>
 
<Item.Group class="max-w-sm">
	{#each people as person (person.username)}
		<Item.Root variant="outline">
			<Item.Media>
				<Avatar.Root>
					<Avatar.Image src={person.avatar} class="grayscale" />
					<Avatar.Fallback>{person.username.charAt(0)}</Avatar.Fallback>
				</Avatar.Root>
			</Item.Media>
			<Item.Content class="gap-1">
				<Item.Title>{person.username}</Item.Title>
				<Item.Description>{person.email}</Item.Description>
			</Item.Content>
			<Item.Actions>
				<Button variant="ghost" size="icon" class="rounded-full">
					<Plus />
				</Button>
			</Item.Actions>
		</Item.Root>
	{/each}
</Item.Group>

Use Item.Header to add a header above the item content.

v0-1.5-sm
v0-1.5-sm

Everyday tasks and UI generation.

v0-1.5-lg
v0-1.5-lg

Advanced thinking or reasoning.

v0-2.0-mini
v0-2.0-mini

Open Source model for everyone.

<script lang="ts">
	import * as Item from "$lib/components/ui/item/index.js";
 
	const models = [
		{
			name: "v0-1.5-sm",
			description: "Everyday tasks and UI generation.",
			image:
				"https://images.unsplash.com/photo-1650804068570-7fb2e3dbf888?q=80&w=640&auto=format&fit=crop",
			credit: "Valeria Reverdo on Unsplash",
		},
		{
			name: "v0-1.5-lg",
			description: "Advanced thinking or reasoning.",
			image:
				"https://images.unsplash.com/photo-1610280777472-54133d004c8c?q=80&w=640&auto=format&fit=crop",
			credit: "Michael Oeser on Unsplash",
		},
		{
			name: "v0-2.0-mini",
			description: "Open Source model for everyone.",
			image:
				"https://images.unsplash.com/photo-1602146057681-08560aee8cde?q=80&w=640&auto=format&fit=crop",
			credit: "Cherry Laithang on Unsplash",
		},
	];
</script>
 
<div class="flex w-full max-w-xl flex-col gap-6">
	<Item.Group class="grid grid-cols-3 gap-4">
		{#each models as model (model.name)}
			<Item.Root variant="outline">
				<Item.Header>
					<img
						src={model.image}
						alt={model.name}
						width={128}
						height={128}
						class="aspect-square w-full rounded-sm object-cover"
					/>
				</Item.Header>
				<Item.Content>
					<Item.Title>{model.name}</Item.Title>
					<Item.Description>{model.description}</Item.Description>
				</Item.Content>
			</Item.Root>
		{/each}
	</Item.Group>
</div>

Use the child snippet to render the item as a link. The hover and focus states will be applied to the anchor element.

<script lang="ts">
	import ChevronRightIcon from "@lucide/svelte/icons/chevron-right";
	import ExternalLinkIcon from "@lucide/svelte/icons/external-link";
	import * as Item from "$lib/components/ui/item/index.js";
</script>
 
<div class="flex w-full max-w-md flex-col gap-4">
	<Item.Root>
		{#snippet child({ props })}
			<a href="##" {...props}>
				<Item.Content>
					<Item.Title>Visit our documentation</Item.Title>
					<Item.Description>Learn how to get started with our components.</Item.Description>
				</Item.Content>
				<Item.Actions>
					<ChevronRightIcon class="size-4" />
				</Item.Actions>
			</a>
		{/snippet}
	</Item.Root>
	<Item.Root variant="outline">
		{#snippet child({ props })}
			<a href="##" target="_blank" rel="noopener noreferrer" {...props}>
				<Item.Content>
					<Item.Title>External resource</Item.Title>
					<Item.Description>Opens in a new tab with security attributes.</Item.Description>
				</Item.Content>
				<Item.Actions>
					<ExternalLinkIcon class="size-4" />
				</Item.Actions>
			</a>
		{/snippet}
	</Item.Root>
</div>
<Item.Root>
  {#snippet child({ props })}
    <a href="/dashboard" {...props}>
      <Item.Media variant="icon">
        <HomeIcon />
      </Item.Media>
      <Item.Content>
        <Item.Title>Dashboard</Item.Title>
        <Item.Description
          >Overview of your account and activity.</Item.Description
        >
      </Item.Content>
    </a>
  {/snippet}
</Item.Root>
<script lang="ts">
	import ChevronDown from "@lucide/svelte/icons/chevron-down";
	import * as Avatar from "$lib/components/ui/avatar/index.js";
	import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js";
	import * as Item from "$lib/components/ui/item/index.js";
	import { Button } from "$lib/components/ui/button/index.js";
 
	const people = [
		{
			username: "shadcn",
			avatar: "https://github.com/shadcn.png",
			email: "shadcn@vercel.com",
		},
		{
			username: "maxleiter",
			avatar: "https://github.com/maxleiter.png",
			email: "maxleiter@vercel.com",
		},
		{
			username: "evilrabbit",
			avatar: "https://github.com/evilrabbit.png",
			email: "evilrabbit@vercel.com",
		},
	];
</script>
 
<DropdownMenu.Root>
	<DropdownMenu.Trigger>
		{#snippet child({ props })}
			<Button {...props} variant="outline">
				Select <ChevronDown />
			</Button>
		{/snippet}
	</DropdownMenu.Trigger>
	<DropdownMenu.Content class="w-auto" align="end">
		<DropdownMenu.Group>
			{#each people as person (person.username)}
				<DropdownMenu.Item>
					<Item.Root size="xs" class="w-full p-2">
						<Item.Media>
							<Avatar.Root class="size-[--spacing(6.5)]">
								<Avatar.Image src={person.avatar} class="grayscale" />
								<Avatar.Fallback>{person.username.charAt(0)}</Avatar.Fallback>
							</Avatar.Root>
						</Item.Media>
						<Item.Content class="gap-0">
							<Item.Title>{person.username}</Item.Title>
							<Item.Description class="leading-none">{person.email}</Item.Description>
						</Item.Content>
					</Item.Root>
				</DropdownMenu.Item>
			{/each}
		</DropdownMenu.Group>
	</DropdownMenu.Content>
</DropdownMenu.Root>