Command Palette

Search for a command...

Item

A versatile component that you can use to display any content.

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 ItemGroup component to create a list of items.

You can pretty much achieve the same result with the div element and some classes, but I've built this so many times that I decided to create a component for it. Now I use it all the time.

Basic Item

A simple item with title and description.

Your profile has been verified.
import { LuBadgeCheck, LuChevronRight } from "react-icons/lu";
import { css } from "styled-system/css";
import { styled } from "styled-system/jsx";
import { Button } from "@/components/ui/button";
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item";

export default function ItemDemo() {
  return (
    <styled.div css={{ display: "flex", w: "full", maxW: "md", flexDir: "column", gap: "6" }}>
      <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>
            <LuBadgeCheck className={css({ w: "5", h: "5" })} />
          </ItemMedia>
          <ItemContent>
            <ItemTitle>Your profile has been verified.</ItemTitle>
          </ItemContent>
          <ItemActions>
            <LuChevronRight className={css({ w: "4", h: "4" })} />
          </ItemActions>
        </a>
      </Item>
    </styled.div>
  );
}

Installation

npx nore-ui-cli@latest add item

Usage

import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemFooter,
  ItemHeader,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item";
<Item>
  <ItemHeader>Item Header</ItemHeader>
  <ItemMedia />
  <ItemContent>
    <ItemTitle>Item</ItemTitle>
    <ItemDescription>Item</ItemDescription>
  </ItemContent>
  <ItemActions />
  <ItemFooter>Item Footer</ItemFooter>
</Item>

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.

Examples

Variants

Default Variant

Standard styling with subtle background and borders.

Outline Variant

Outlined style with clear borders and transparent background.

Muted Variant

Subdued appearance with muted colors for secondary content.

import { styled } from "styled-system/jsx";
import { Button } from "@/components/ui/button";
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemTitle,
} from "@/components/ui/item";

export default function ItemVariant() {
  return (
    <styled.div css={{ display: "flex", flexDir: "column", gap: "6" }}>
      <Item>
        <ItemContent>
          <ItemTitle>Default Variant</ItemTitle>
          <ItemDescription>Standard styling with subtle background and borders.</ItemDescription>
        </ItemContent>
        <ItemActions>
          <Button variant="outline" size="sm">
            Open
          </Button>
        </ItemActions>
      </Item>
      <Item variant="outline">
        <ItemContent>
          <ItemTitle>Outline Variant</ItemTitle>
          <ItemDescription>
            Outlined style with clear borders and transparent background.
          </ItemDescription>
        </ItemContent>
        <ItemActions>
          <Button variant="outline" size="sm">
            Open
          </Button>
        </ItemActions>
      </Item>
      <Item variant="muted">
        <ItemContent>
          <ItemTitle>Muted Variant</ItemTitle>
          <ItemDescription>
            Subdued appearance with muted colors for secondary content.
          </ItemDescription>
        </ItemContent>
        <ItemActions>
          <Button variant="outline" size="sm">
            Open
          </Button>
        </ItemActions>
      </Item>
    </styled.div>
  );
}

Size

The Item component has different sizes for different use cases. For example, you can use the sm size for a compact item or the default size for a standard item.

Basic Item

A simple item with title and description.

Your profile has been verified.
import { LuBadgeCheck, LuChevronRight } from "react-icons/lu";
import { css } from "styled-system/css";
import { styled } from "styled-system/jsx";
import { Button } from "@/components/ui/button";
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item";

export default function ItemSizeDemo() {
  return (
    <styled.div css={{ display: "flex", w: "full", maxW: "md", flexDir: "column", gap: "6" }}>
      <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>
            <LuBadgeCheck className={css({ w: "5", h: "5" })} />
          </ItemMedia>
          <ItemContent>
            <ItemTitle>Your profile has been verified.</ItemTitle>
          </ItemContent>
          <ItemActions>
            <LuChevronRight className={css({ w: "4", h: "4" })} />
          </ItemActions>
        </a>
      </Item>
    </styled.div>
  );
}

Icon

Security Alert

New login detected from unknown device.

import { LuShieldAlert } from "react-icons/lu";
import { styled } from "styled-system/jsx";
import { Button } from "@/components/ui/button";
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item";

export default function ItemIcon() {
  return (
    <styled.div css={{ display: "flex", w: "full", maxW: "lg", flexDir: "column", gap: "6" }}>
      <Item variant="outline">
        <ItemMedia variant="icon">
          <LuShieldAlert />
        </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>
    </styled.div>
  );
}

Avatar

ER
Evil Rabbit

Last seen 5 months ago

CNLRER
No Team Members

Invite your team to collaborate on this project.

import { LuPlus } from "react-icons/lu";
import { styled } from "styled-system/jsx";
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 default function ItemAvatar() {
  return (
    <styled.div css={{ display: "flex", w: "full", maxW: "lg", flexDir: "column", gap: "6" }}>
      <Item variant="outline">
        <ItemMedia>
          <Avatar css={{ w: "10", h: "10" }}>
            <AvatarImage src="https://github.com/evilrabbit.png" />
            <AvatarFallback>ER</AvatarFallback>
          </Avatar>
        </ItemMedia>
        <ItemContent>
          <ItemTitle>Evil Rabbit</ItemTitle>
          <ItemDescription>Last seen 5 months ago</ItemDescription>
        </ItemContent>
        <ItemActions>
          <Button size="icon-sm" variant="outline" css={{ rounded: "full" }} aria-label="Invite">
            <LuPlus />
          </Button>
        </ItemActions>
      </Item>
      <Item variant="outline">
        <ItemMedia>
          <styled.div
            css={{
              display: "flex",
              spaceX: "-2",
              "& > .avatar__root": {
                outlineWidth: "2px",
                outlineColor: "bg",
                filter: "grayscale(1)",
              },
            }}
          >
            <Avatar css={{ display: "none", sm: { display: "flex" } }}>
              <AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
              <AvatarFallback>CN</AvatarFallback>
            </Avatar>
            <Avatar css={{ display: "none", sm: { display: "flex" } }}>
              <AvatarImage src="https://github.com/maxleiter.png" alt="@maxleiter" />
              <AvatarFallback>LR</AvatarFallback>
            </Avatar>
            <Avatar>
              <AvatarImage src="https://github.com/evilrabbit.png" alt="@evilrabbit" />
              <AvatarFallback>ER</AvatarFallback>
            </Avatar>
          </styled.div>
        </ItemMedia>
        <ItemContent>
          <ItemTitle>No Team Members</ItemTitle>
          <ItemDescription>Invite your team to collaborate on this project.</ItemDescription>
        </ItemContent>
        <ItemActions>
          <Button size="sm" variant="outline">
            Invite
          </Button>
        </ItemActions>
      </Item>
    </styled.div>
  );
}

Image

import Image from "next/image";
import { css } from "styled-system/css";
import { styled } from "styled-system/jsx";
import {
  Item,
  ItemContent,
  ItemDescription,
  ItemGroup,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item";

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",
  },
];

const generateSvgUrl = (text: string) => {
  const hash = text.split("").reduce((acc, char) => acc + char.charCodeAt(0), 0);
  const hue = hash % 360;
  const svg = `<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg"><rect width="32" height="32" fill="hsl(${hue}, 70%, 50%)"/></svg>`;
  return `data:image/svg+xml,${encodeURIComponent(svg)}`;
};

export default function ItemImage() {
  return (
    <styled.div css={{ display: "flex", w: "full", maxW: "md", flexDir: "column", gap: "6" }}>
      <ItemGroup css={{ gap: "4" }}>
        {music.map((song) => (
          <Item key={song.title} variant="outline" asChild role="listitem">
            <a href="#">
              <ItemMedia variant="image">
                <Image
                  src={generateSvgUrl(song.title)}
                  alt={song.title}
                  width={32}
                  height={32}
                  className={css({ objectFit: "cover", filter: "grayscale(1)" })}
                />
              </ItemMedia>
              <ItemContent>
                <ItemTitle css={{ lineClamp: "1" }}>
                  {song.title} - <styled.span css={{ color: "muted.fg" }}>{song.album}</styled.span>
                </ItemTitle>
                <ItemDescription>{song.artist}</ItemDescription>
              </ItemContent>
              <ItemContent css={{ flex: "none", textAlign: "center" }}>
                <ItemDescription>{song.duration}</ItemDescription>
              </ItemContent>
            </a>
          </Item>
        ))}
      </ItemGroup>
    </styled.div>
  );
}

Group

import * as React from "react";
import { LuPlus } from "react-icons/lu";
import { styled } from "styled-system/jsx";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemGroup,
  ItemMedia,
  ItemSeparator,
  ItemTitle,
} from "@/components/ui/item";

const people = [
  {
    username: "shadcn",
    avatar: "https://github.com/shadcn.png",
    email: "[email protected]",
  },
  {
    username: "maxleiter",
    avatar: "https://github.com/maxleiter.png",
    email: "[email protected]",
  },
  {
    username: "evilrabbit",
    avatar: "https://github.com/evilrabbit.png",
    email: "[email protected]",
  },
];

export default function ItemGroupExample() {
  return (
    <styled.div css={{ display: "flex", w: "full", maxW: "md", flexDir: "column", gap: "6" }}>
      <ItemGroup>
        {people.map((person, index) => (
          <React.Fragment key={person.username}>
            <Item>
              <ItemMedia>
                <Avatar>
                  <AvatarImage src={person.avatar} css={{ filter: "grayscale(1)" }} />
                  <AvatarFallback>{person.username.charAt(0)}</AvatarFallback>
                </Avatar>
              </ItemMedia>
              <ItemContent css={{ gap: "1" }}>
                <ItemTitle>{person.username}</ItemTitle>
                <ItemDescription>{person.email}</ItemDescription>
              </ItemContent>
              <ItemActions>
                <Button variant="ghost" size="icon" css={{ rounded: "full" }}>
                  <LuPlus />
                </Button>
              </ItemActions>
            </Item>
            {index !== people.length - 1 && <ItemSeparator />}
          </React.Fragment>
        ))}
      </ItemGroup>
    </styled.div>
  );
}
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.

import Image from "next/image";
import { css } from "styled-system/css";
import { styled } from "styled-system/jsx";
import {
  Item,
  ItemContent,
  ItemDescription,
  ItemGroup,
  ItemHeader,
  ItemTitle,
} from "@/components/ui/item";

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",
  },
];

export default function ItemHeaderDemo() {
  return (
    <styled.div css={{ display: "flex", w: "full", maxW: "xl", flexDir: "column", gap: "6" }}>
      <ItemGroup
        css={{ display: "grid", gridTemplateColumns: "repeat(3, minmax(0, 1fr))", gap: "4" }}
      >
        {models.map((model) => (
          <Item key={model.name} variant="outline">
            <ItemHeader>
              <Image
                src={model.image}
                alt={model.name}
                width={128}
                height={128}
                className={css({
                  aspectRatio: "square",
                  w: "full",
                  rounded: "sm",
                  objectFit: "cover",
                })}
              />
            </ItemHeader>
            <ItemContent>
              <ItemTitle>{model.name}</ItemTitle>
              <ItemDescription>{model.description}</ItemDescription>
            </ItemContent>
          </Item>
        ))}
      </ItemGroup>
    </styled.div>
  );
}

To render an item as a link, use the asChild prop. The hover and focus states will be applied to the anchor element.

import { LuChevronRight, LuExternalLink } from "react-icons/lu";
import { css } from "styled-system/css";
import { styled } from "styled-system/jsx";
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemTitle,
} from "@/components/ui/item";

export default function ItemLink() {
  return (
    <styled.div css={{ display: "flex", w: "full", maxW: "md", flexDir: "column", gap: "4" }}>
      <Item asChild>
        <a href="#">
          <ItemContent>
            <ItemTitle>Visit our documentation</ItemTitle>
            <ItemDescription>Learn how to get started with our components.</ItemDescription>
          </ItemContent>
          <ItemActions>
            <LuChevronRight className={css({ w: "4", h: "4" })} />
          </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>
            <LuExternalLink className={css({ w: "4", h: "4" })} />
          </ItemActions>
        </a>
      </Item>
    </styled.div>
  );
}
<Item asChild>
  <a href="/dashboard">
    <ItemMedia />
    <ItemContent>
      <ItemTitle>Dashboard</ItemTitle>
      <ItemDescription>Overview of your account and activity.</ItemDescription>
    </ItemContent>
    <ItemActions />
  </a>
</Item>
"use client";

import { LuChevronDown } from "react-icons/lu";
import { styled } from "styled-system/jsx";
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 = [
  {
    username: "shadcn",
    avatar: "https://github.com/shadcn.png",
    email: "[email protected]",
  },
  {
    username: "maxleiter",
    avatar: "https://github.com/maxleiter.png",
    email: "[email protected]",
  },
  {
    username: "evilrabbit",
    avatar: "https://github.com/evilrabbit.png",
    email: "[email protected]",
  },
];

export default function ItemDropdown() {
  return (
    <styled.div
      css={{
        display: "flex",
        minH: "64",
        w: "full",
        maxW: "md",
        flexDir: "column",
        alignItems: "center",
        gap: "6",
      }}
    >
      <DropdownMenu>
        <DropdownMenuTrigger asChild>
          <Button variant="outline" size="sm" css={{ w: "fit" }}>
            Select <LuChevronDown />
          </Button>
        </DropdownMenuTrigger>
        <DropdownMenuContent css={{ w: "72" }} align="end">
          {people.map((person) => (
            <DropdownMenuItem key={person.username} css={{ p: "0" }}>
              <Item size="sm" css={{ w: "full", p: "2" }}>
                <ItemMedia>
                  <Avatar css={{ w: "8", h: "8" }}>
                    <AvatarImage src={person.avatar} css={{ filter: "grayscale(1)" }} />
                    <AvatarFallback>{person.username.charAt(0)}</AvatarFallback>
                  </Avatar>
                </ItemMedia>
                <ItemContent css={{ gap: "0.5" }}>
                  <ItemTitle>{person.username}</ItemTitle>
                  <ItemDescription>{person.email}</ItemDescription>
                </ItemContent>
              </Item>
            </DropdownMenuItem>
          ))}
        </DropdownMenuContent>
      </DropdownMenu>
    </styled.div>
  );
}

API Reference

Item

The main component for displaying content with media, title, description, and actions.

PropTypeDefault
variant"default" | "outline" | "muted""default"
size"default" | "sm""default"
asChildbooleanfalse
<Item size="" variant="">
  <ItemMedia />
  <ItemContent>
    <ItemTitle>Item</ItemTitle>
    <ItemDescription>Item</ItemDescription>
  </ItemContent>
  <ItemActions />
</Item>

You can use the asChild prop to render a custom component as the item, for example a link. The hover and focus states will be applied to the custom component.

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

export function ItemLink() {
  return (
    <Item asChild>
      <a href="/dashboard">
        <ItemMedia variant="icon">
          <Home />
        </ItemMedia>
        <ItemContent>
          <ItemTitle>Dashboard</ItemTitle>
          <ItemDescription>Overview of your account and activity.</ItemDescription>
        </ItemContent>
      </a>
    </Item>
  );
}

ItemGroup

The ItemGroup component is a container that groups related items together with consistent styling.

PropTypeDefault
cssSystemStyleObject
<ItemGroup>
  <Item />
  <Item />
</ItemGroup>

ItemSeparator

The ItemSeparator component is a separator that separates items in the item group.

PropTypeDefault
cssSystemStyleObject
<ItemGroup>
  <Item />
  <ItemSeparator />
  <Item />
</ItemGroup>

ItemMedia

Use the ItemMedia component to display media content such as icons, images, or avatars.

PropTypeDefault
variant"default" | "icon" | "image""default"
cssSystemStyleObject
<ItemMedia variant="icon">
  <Icon />
</ItemMedia>
<ItemMedia variant="image">
  <img src="..." alt="..." />
</ItemMedia>

ItemContent

The ItemContent component wraps the title and description of the item.

You can skip ItemContent if you only need a title.

PropTypeDefault
cssSystemStyleObject
<ItemContent>
  <ItemTitle>Item</ItemTitle>
  <ItemDescription>Item</ItemDescription>
</ItemContent>

ItemTitle

Use the ItemTitle component to display the title of the item.

PropTypeDefault
cssSystemStyleObject
<ItemTitle>Item Title</ItemTitle>

ItemDescription

Use the ItemDescription component to display the description of the item.

PropTypeDefault
cssSystemStyleObject
<ItemDescription>Item description</ItemDescription>

ItemActions

Use the ItemActions component to display action buttons or other interactive elements.

PropTypeDefault
cssSystemStyleObject
<ItemActions>
  <Button>Action</Button>
  <Button>Action</Button>
</ItemActions>

ItemHeader

Use the ItemHeader component to display a header in the item.

PropTypeDefault
cssSystemStyleObject
<ItemHeader>Item Header</ItemHeader>

ItemFooter

Use the ItemFooter component to display a footer in the item.

PropTypeDefault
cssSystemStyleObject
<ItemFooter>Item Footer</ItemFooter>