Item
A versatile component for displaying any content, combining elements like title, description, media, and actions.
Basic Item
A simple item with title and description.
Your profile has been verified.
---import { BadgeCheckIcon, ChevronRightIcon } from '@lucide/astro';
import Button from '@bejamas/ui/components/Button.astro';import Item from '@bejamas/ui/components/Item.astro';---
<div class="flex w-full max-w-md flex-col gap-6"> <Item variant="outline"> <Item part="content"> <Item part="title">Basic Item</Item> <Item part="description">A simple item with title and description.</Item> </Item> <Item part="actions"><Button variant="outline" size="sm">Action</Button></Item> </Item> <Item variant="outline" size="sm" as="a" href="#"> <Item part="media"><BadgeCheckIcon class="size-5" /></Item> <Item part="content"> <Item part="title">Your profile has been verified.</Item> </Item> <Item part="actions"><ChevronRightIcon class="size-4" /></Item> </Item></div>Installation
Section titled “Installation” bunx bejamas add item npx bejamas add item pnpm dlx bejamas add item yarn dlx bejamas add item---/** * @component Item * @title Item * @description A versatile component for displaying any content, combining elements like title, description, media, and actions. * * @preview * * <div class="flex w-full max-w-md flex-col gap-6"> * <Item variant="outline"> * <Item part="content"> * <Item part="title">Basic Item</Item> * <Item part="description">A simple item with title and description.</Item> * </Item> * <Item part="actions"><Button variant="outline" size="sm">Action</Button></Item> * </Item> * <Item variant="outline" size="sm" as="a" href="#"> * <Item part="media"><BadgeCheckIcon class="size-5" /></Item> * <Item part="content"> * <Item part="title">Your profile has been verified.</Item> * </Item> * <Item part="actions"><ChevronRightIcon class="size-4" /></Item> * </Item> * </div> * * @usage * * ```astro * --- * import Item from '@/components/ui/Item.astro'; * --- * * <Item variant="outline"> * <Item part="header"> * <Item part="title">Basic Item</Item> * <Item part="description">A simple item with title and description.</Item> * </Item> * <Item part="media"> * <BadgeCheckIcon class="size-5" /> * </Item> * <Item part="content"> * Content * </Item> * <Item part="actions"> * Actions * </Item> * <Item part="footer">Item Footer</Item> * </Item> * ``` * * @examples * * ### Separator * * Use `<Item part="separator" />` to separate items. * * <div class="space-y-5"> * <Item variant="outline"> * <Item part="content"> * <Item part="title">Item title</Item> * <Item part="description">Short description for the item.</Item> * </Item> * <Item part="actions"><Button variant="outline" size="sm">Action</Button></Item> * </Item> * * <Item part="separator" /> * * <Item part="group"> * <Item> * <Item part="content"> * <Item part="title">Item title</Item> * <Item part="description">Short description for the item.</Item> * </Item> * <Item part="actions"><Button variant="outline" size="sm">Action</Button></Item> * </Item> * </Item> * </div> * * ### Variants * * <div class="flex flex-col gap-6"> * <Item> * <Item part="content"> * <Item part="title">Default Variant</Item> * <Item part="description">Standard styling with subtle background and borders.</Item> * </Item> * <Item part="actions"><Button variant="outline" size="sm">Open</Button></Item> * </Item> * <Item variant="outline"> * <Item part="content"> * <Item part="title">Outline Variant</Item> * <Item part="description">Outlined style with clear borders and transparent background.</Item> * </Item> * <Item part="actions"><Button variant="outline" size="sm">Open</Button></Item> * </Item> * <Item variant="muted"> * <Item part="content"> * <Item part="title">Muted Variant</Item> * <Item part="description">Subdued appearance with muted colors for secondary content.</Item> * </Item> * <Item part="actions"><Button variant="outline" size="sm">Open</Button></Item> * </Item> * </div> * * ### Icon * * <div class="flex w-full max-w-lg flex-col gap-6"> * <Item variant="outline"> * <Item part="media" mediaVariant="icon"><ShieldAlertIcon /></Item> * <Item part="content"> * <Item part="title">Security Alert</Item> * <Item part="description">New login detected from unknown device.</Item> * </Item> * <Item part="actions"><Button size="sm" variant="outline">Review</Button></Item> * </Item> * </div>
* ### Image * * <div class="flex w-full max-w-md flex-col gap-6"> * <Item part="group" class="gap-4"> * <Item variant="outline" as="a" href="#" role="listitem"> * <Item part="media" mediaVariant="image"> * <img * src={`https://avatar.vercel.sh/Midnight City Lights`} * alt="Midnight City Lights" * width={32} * height={32} * class="object-cover grayscale" * /> * </Item> * <Item part="content"> * <Item part="title"> * Midnight City Lights - <span class="text-muted-foreground">Electric Nights</span> * </Item> * <Item part="description">Neon Dreams - Electric Nights</Item> * </Item> * </Item> * </Item> * </div> * * ### Header * * <div class="flex w-full max-w-xl flex-col gap-6"> * <Item part="group" class="grid grid-cols-3 gap-4"> * <Item variant="outline"> * <Item part="header"> * <img * src="https://images.unsplash.com/photo-1650804068570-7fb2e3dbf888?q=80&w=640&auto=format&fit=crop" * alt="v0-1.5-sm" * width={128} * height={128} * class="aspect-square w-full rounded-sm object-cover" * /> * </Item> * <Item part="title">v0-1.5-sm</Item> * <Item part="description">Everyday tasks and UI generation.</Item> * </Item> * </Item> * </div> * * ### Link * * To render an item as a link, use the `as` prop. The hover and focus states will be applied to the anchor element. * * <div class="flex w-full max-w-xl flex-col gap-6"> * <Item part="group" class="grid grid-cols-3 gap-4"> * <Item variant="outline" as="a" href="#"> * <Item part="header"> * <img * src="https://images.unsplash.com/photo-1650804068570-7fb2e3dbf888?q=80&w=640&auto=format&fit=crop" * alt="v0-1.5-sm" * width={128} * height={128} * class="aspect-square w-full rounded-sm object-cover" * /> * </Item> * <Item part="title">v0-1.5-sm</Item> * <Item part="description">Everyday tasks and UI generation.</Item> * </Item> * </Item> * </div> */
import type { HTMLAttributes, HTMLTag } from "astro/types";import { cva } from "class-variance-authority";import { cn } from "@bejamas/ui/lib/utils";import Separator from "@bejamas/ui/components/Separator.astro";
type ItemRootVariant = "default" | "outline" | "muted";type ItemRootSize = "default" | "sm";type ItemMediaVariant = "default" | "icon" | "image";
type ItemPart = | "root" | "group" | "separator" | "media" | "content" | "title" | "description" | "actions" | "header" | "footer";
type ItemRootProps = { part?: "root"; as?: HTMLTag; variant?: ItemRootVariant; size?: ItemRootSize; class?: string;} & HTMLAttributes<"div">;
type ItemGroupProps = { part: "group"; as?: HTMLTag; class?: string;} & HTMLAttributes<"div">;
type ItemSeparatorProps = { part: "separator"; as?: HTMLTag; class?: string;} & HTMLAttributes<"div">;
type ItemMediaProps = { part: "media"; as?: HTMLTag; mediaVariant?: ItemMediaVariant; variant?: never; size?: never; class?: string;} & HTMLAttributes<"div">;
type ItemContentProps = { part: "content"; as?: HTMLTag; variant?: never; size?: never; class?: string;} & HTMLAttributes<"div">;
type ItemTitleProps = { part: "title"; as?: HTMLTag; variant?: never; size?: never; class?: string;} & HTMLAttributes<"div">;
type ItemDescriptionProps = { part: "description"; as?: HTMLTag; variant?: never; size?: never; class?: string;} & HTMLAttributes<"p">;
type ItemActionsProps = { part: "actions"; as?: HTMLTag; variant?: never; size?: never; class?: string;} & HTMLAttributes<"div">;
type ItemHeaderProps = { part: "header"; as?: HTMLTag; variant?: never; size?: never; class?: string;} & HTMLAttributes<"div">;
type ItemFooterProps = { part: "footer"; as?: HTMLTag; variant?: never; size?: never; class?: string;} & HTMLAttributes<"div">;
type Props = | ItemRootProps | ItemGroupProps | ItemSeparatorProps | ItemMediaProps | ItemContentProps | ItemTitleProps | ItemDescriptionProps | ItemActionsProps | ItemHeaderProps | ItemFooterProps;
const { part: rawPart, as: Tag = "div" as HTMLTag, class: className = "", variant, size, mediaVariant, ...rest} = Astro.props as Props;
const part: ItemPart = (rawPart ?? "root") as ItemPart;
// Variants for the item container (matches shadcn styles)const itemVariants = cva( "group/item flex items-center border border-transparent text-sm rounded-md transition-colors [a]:hover:bg-accent/5 [a]:transition-colors duration-100 flex-wrap outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", { variants: { variant: { default: "bg-transparent", outline: "border-border", muted: "bg-muted/50", }, size: { default: "p-4 gap-4", sm: "py-3 px-4 gap-2.5", }, }, defaultVariants: { variant: "default", size: "default", }, },);
// Variants for media slot wrapperconst itemMediaVariants = cva( "flex shrink-0 items-center justify-center gap-2 group-has-[[data-slot=item-description]]/item:self-start [&_svg]:pointer-events-none group-has-[[data-slot=item-description]]/item:translate-y-0.5", { variants: { variant: { default: "bg-transparent", icon: "size-8 border rounded-sm bg-muted [&_svg:not([class*='size-'])]:size-4", image: "size-10 rounded-sm overflow-hidden [&_img]:size-full [&_img]:object-cover", }, }, defaultVariants: { variant: "default", }, },);---
{ part === "group" && ( <Tag {...rest} role="list" data-slot="item-group" class={cn("group/item-group flex flex-col", className)} > <slot /> </Tag> )}
{ part === "content" && ( <Tag {...rest} data-slot="item-content" class={cn( "flex flex-1 flex-col gap-1 [&+[data-slot=item-content]]:flex-none", className, )} > <slot /> </Tag> )}
{ part === "separator" && ( <Separator {...rest} data-slot="item-separator" aria-hidden="true" class={cn("my-0", className)} /> )}
{ part === "root" && ( <Tag {...rest} data-slot="item" data-variant={(variant as ItemRootVariant) ?? "default"} data-size={(size as ItemRootSize) ?? "default"} class={cn( itemVariants({ variant: (variant as ItemRootVariant) ?? "default", size: (size as ItemRootSize) ?? "default", }), className, )} > <slot /> </Tag> )}
{ part === "media" && ( <Tag {...rest} data-slot="item-media" class={cn( itemMediaVariants({ variant: (mediaVariant as ItemMediaVariant) ?? "default", }), className, )} > <slot /> </Tag> )}
{ part === "title" && ( <Tag {...rest} data-slot="item-title" class={cn( "flex w-fit items-center gap-2 text-sm leading-snug font-medium", className, )} > <slot /> </Tag> )}
{ part === "description" && ( <Tag {...rest} data-slot="item-description" class={cn( "text-muted-foreground line-clamp-2 text-sm leading-normal font-normal text-balance", "[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4", className, )} > <slot /> </Tag> )}
{ part === "actions" && ( <Tag {...rest} data-slot="item-actions" class={cn("flex items-center gap-2", className)} > <slot /> </Tag> )}
{ part === "header" && ( <Tag {...rest} data-slot="item-header" class={cn( "flex basis-full items-center justify-between gap-2", className, )} > <slot /> </Tag> )}
{ part === "footer" && ( <Tag {...rest} data-slot="item-footer" class={cn( "flex basis-full items-center justify-between gap-2", className, )} > <slot /> </Tag> )}---import Item from '@/components/ui/Item.astro';---
<Item variant="outline"> <Item part="header"> <Item part="title">Basic Item</Item> <Item part="description">A simple item with title and description.</Item> </Item> <Item part="media"> <BadgeCheckIcon class="size-5" /> </Item> <Item part="content"> Content </Item> <Item part="actions"> Actions </Item> <Item part="footer">Item Footer</Item></Item>Examples
Section titled “Examples”Separator
Section titled “Separator”Use <Item part="separator" /> to separate items.
Item title
Short description for the item.
Item title
Short description for the item.
---import Button from '@bejamas/ui/components/Button.astro';import Item from '@bejamas/ui/components/Item.astro';---
<div class="space-y-5"> <Item variant="outline"> <Item part="content"> <Item part="title">Item title</Item> <Item part="description">Short description for the item.</Item> </Item> <Item part="actions"><Button variant="outline" size="sm">Action</Button></Item> </Item>
<Item part="separator" />
<Item part="group"> <Item> <Item part="content"> <Item part="title">Item title</Item> <Item part="description">Short description for the item.</Item> </Item> <Item part="actions"><Button variant="outline" size="sm">Action</Button></Item> </Item> </Item></div>Variants
Section titled “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 Button from '@bejamas/ui/components/Button.astro';import Item from '@bejamas/ui/components/Item.astro';---
<div class="flex flex-col gap-6"> <Item> <Item part="content"> <Item part="title">Default Variant</Item> <Item part="description">Standard styling with subtle background and borders.</Item> </Item> <Item part="actions"><Button variant="outline" size="sm">Open</Button></Item> </Item> <Item variant="outline"> <Item part="content"> <Item part="title">Outline Variant</Item> <Item part="description">Outlined style with clear borders and transparent background.</Item> </Item> <Item part="actions"><Button variant="outline" size="sm">Open</Button></Item> </Item> <Item variant="muted"> <Item part="content"> <Item part="title">Muted Variant</Item> <Item part="description">Subdued appearance with muted colors for secondary content.</Item> </Item> <Item part="actions"><Button variant="outline" size="sm">Open</Button></Item> </Item></div>Security Alert
New login detected from unknown device.
---import { ShieldAlertIcon } from '@lucide/astro';
import Button from '@bejamas/ui/components/Button.astro';import Item from '@bejamas/ui/components/Item.astro';---
<div class="flex w-full max-w-lg flex-col gap-6"> <Item variant="outline"> <Item part="media" mediaVariant="icon"><ShieldAlertIcon /></Item> <Item part="content"> <Item part="title">Security Alert</Item> <Item part="description">New login detected from unknown device.</Item> </Item> <Item part="actions"><Button size="sm" variant="outline">Review</Button></Item> </Item></div>---import Item from '@bejamas/ui/components/Item.astro';---
<div class="flex w-full max-w-md flex-col gap-6"> <Item part="group" class="gap-4"> <Item variant="outline" as="a" href="#" role="listitem"> <Item part="media" mediaVariant="image"> <img src={`https://avatar.vercel.sh/Midnight City Lights`} alt="Midnight City Lights" width={32} height={32} class="object-cover grayscale" /> </Item> <Item part="content"> <Item part="title"> Midnight City Lights - <span class="text-muted-foreground">Electric Nights</span> </Item> <Item part="description">Neon Dreams - Electric Nights</Item> </Item> </Item> </Item></div>Header
Section titled “Header”v0-1.5-sm
Everyday tasks and UI generation.
---import Item from '@bejamas/ui/components/Item.astro';---
<div class="flex w-full max-w-xl flex-col gap-6"> <Item part="group" class="grid grid-cols-3 gap-4"> <Item variant="outline"> <Item part="header"> <img src="https://images.unsplash.com/photo-1650804068570-7fb2e3dbf888?q=80&w=640&auto=format&fit=crop" alt="v0-1.5-sm" width={128} height={128} class="aspect-square w-full rounded-sm object-cover" /> </Item> <Item part="title">v0-1.5-sm</Item> <Item part="description">Everyday tasks and UI generation.</Item> </Item> </Item></div>To render an item as a link, use the as prop. The hover and focus states will be applied to the anchor element.
---import Item from '@bejamas/ui/components/Item.astro';---
<div class="flex w-full max-w-xl flex-col gap-6"> <Item part="group" class="grid grid-cols-3 gap-4"> <Item variant="outline" as="a" href="#"> <Item part="header"> <img src="https://images.unsplash.com/photo-1650804068570-7fb2e3dbf888?q=80&w=640&auto=format&fit=crop" alt="v0-1.5-sm" width={128} height={128} class="aspect-square w-full rounded-sm object-cover" /> </Item> <Item part="title">v0-1.5-sm</Item> <Item part="description">Everyday tasks and UI generation.</Item> </Item> </Item></div>