Item

Flexible row layout with leading media, content, and trailing actions. Install Item from the VLLNT UI registry with the shadcn CLI.

Report a bug

Flexible row layout with leading media, content, and trailing actions. Part of the form family in VLLNT UI, it ships as a machine-readable registry entry — copy the source directly into your app with the shadcn CLI and own it, no runtime dependency on a component library.

Preview

Switch between light and dark to inspect the embedded Storybook preview.

Installation

Add Item to your project with the shadcn CLI. The source lands in your codebase, ready to adapt:

pnpm dlx shadcn@latest add https://ui.vllnt.ai/r/item.json

Source

import * as React from "react"; import { cva, type VariantProps } from "class-variance-authority"; import { cn } from "../../lib/utils"; const itemVariants = cva("flex items-center gap-3 rounded-md text-sm", { defaultVariants: { size: "default", variant: "default", }, variants: { size: { default: "p-3", sm: "p-2", }, variant: { default: "", muted: "bg-muted/50", outline: "border border-border", }, }, }); /** Flexible row with leading media, content, and trailing actions. */ export type ItemProps = React.ComponentPropsWithoutRef<"div"> & VariantProps<typeof itemVariants>; const Item = ({ className, ref, size, variant, ...props }: ItemProps & { ref?: React.Ref<HTMLDivElement> }) => ( <div className={cn(itemVariants({ size, variant }), className)} data-slot="item" ref={ref} {...props} /> ); Item.displayName = "Item"; /** Leading slot for an icon, avatar, or thumbnail. */ export type ItemMediaProps = React.ComponentPropsWithoutRef<"div">; const ItemMedia = ({ className, ref, ...props }: ItemMediaProps & { ref?: React.Ref<HTMLDivElement> }) => ( <div className={cn( "flex shrink-0 items-center justify-center [&_svg]:size-5", className, )} data-slot="item-media" ref={ref} {...props} /> ); ItemMedia.displayName = "ItemMedia"; /** Stacked title and description in the middle of an Item. */ export type ItemContentProps = React.ComponentPropsWithoutRef<"div">; const ItemContent = ({ className, ref, ...props }: ItemContentProps & { ref?: React.Ref<HTMLDivElement> }) => ( <div className={cn("flex min-w-0 flex-1 flex-col gap-0.5", className)} data-slot="item-content" ref={ref} {...props} /> ); ItemContent.displayName = "ItemContent"; /** Primary line of text inside an ItemContent. */ export type ItemTitleProps = React.ComponentPropsWithoutRef<"div">; const ItemTitle = ({ className, ref, ...props }: ItemTitleProps & { ref?: React.Ref<HTMLDivElement> }) => ( <div className={cn("font-medium leading-none", className)} data-slot="item-title" ref={ref} {...props} /> ); ItemTitle.displayName = "ItemTitle"; /** Secondary muted line of text inside an ItemContent. */ export type ItemDescriptionProps = React.ComponentPropsWithoutRef<"p">; const ItemDescription = ({ className, ref, ...props }: ItemDescriptionProps & { ref?: React.Ref<HTMLParagraphElement> }) => ( <p className={cn("text-sm text-muted-foreground", className)} data-slot="item-description" ref={ref} {...props} /> ); ItemDescription.displayName = "ItemDescription"; /** Trailing slot for actions such as buttons or switches. */ export type ItemActionsProps = React.ComponentPropsWithoutRef<"div">; const ItemActions = ({ className, ref, ...props }: ItemActionsProps & { ref?: React.Ref<HTMLDivElement> }) => ( <div className={cn("flex shrink-0 items-center gap-2", className)} data-slot="item-actions" ref={ref} {...props} /> ); ItemActions.displayName = "ItemActions"; export { Item, ItemActions, ItemContent, ItemDescription, ItemMedia, ItemTitle, itemVariants, };

Stories

Explore every variant and state in the interactive Storybook:

Preview

Switch between light and dark to inspect the embedded Storybook preview.

Dependencies

  • @vllnt/ui@^0.3.0