Item
Flexible row with media, title, description and actions. Variants default, outline, muted; sizes default, sm, xs.
7nXK...Qp2d, devnet
Rebalances when drift exceeds 5%.
7nXK...Qp2d, devnet
Rebalances when drift exceeds 5%.
7nXK...Qp2d, devnet
Rebalances when drift exceeds 5%.
import { Button } from "@/components/ui/button";import { Item, ItemActions, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemSeparator, ItemTitle,} from "@/components/ui/item";import { IconPlaceholder } from "@/edmi/icon-placeholder";
export default function Demo() { return ( <div className="flex w-full max-w-md flex-col gap-6"> <Item variant="outline"> <ItemMedia variant="icon"> <IconPlaceholder lucide="WalletIcon" tabler="IconWallet" hugeicons="WalletIcon" phosphor="WalletIcon" remixicon="RiWalletLine" /> </ItemMedia> <ItemContent> <ItemTitle>Phantom wallet</ItemTitle> <ItemDescription>7nXK...Qp2d, devnet</ItemDescription> </ItemContent> <ItemActions> <Button size="sm" variant="outline"> Disconnect </Button> </ItemActions> </Item> <Item variant="muted" size="sm"> <ItemContent> <ItemTitle>Keeper is on</ItemTitle> <ItemDescription>Rebalances when drift exceeds 5%.</ItemDescription> </ItemContent> </Item> <ItemGroup> <Item render={<a href="#profile" />}> <ItemMedia variant="icon"> <IconPlaceholder lucide="UserIcon" tabler="IconUser" hugeicons="UserIcon" phosphor="UserIcon" remixicon="RiUserLine" /> </ItemMedia> <ItemContent> <ItemTitle>Profile</ItemTitle> <ItemDescription>Name, avatar and bio</ItemDescription> </ItemContent> <IconPlaceholder lucide="ChevronRightIcon" tabler="IconChevronRight" hugeicons="ArrowRight01Icon" phosphor="CaretRightIcon" remixicon="RiArrowRightSLine" className="size-4 text-muted-foreground" /> </Item> <ItemSeparator /> <Item render={<a href="#wallets" />}> <ItemMedia variant="icon"> <IconPlaceholder lucide="WalletIcon" tabler="IconWallet" hugeicons="WalletIcon" phosphor="WalletIcon" remixicon="RiWalletLine" /> </ItemMedia> <ItemContent> <ItemTitle>Wallets</ItemTitle> <ItemDescription>2 connected</ItemDescription> </ItemContent> <IconPlaceholder lucide="ChevronRightIcon" tabler="IconChevronRight" hugeicons="ArrowRight01Icon" phosphor="CaretRightIcon" remixicon="RiArrowRightSLine" className="size-4 text-muted-foreground" /> </Item> </ItemGroup> </div> );}<script setup lang="ts">import { ChevronRightIcon, UserIcon, WalletIcon } from "@lucide/vue";import { Button } from "@/components/ui/button";import { Item, ItemActions, ItemContent, ItemDescription, ItemGroup, ItemMedia, ItemSeparator, ItemTitle,} from "@/components/ui/item";</script>
<template> <div class="flex w-full max-w-md flex-col gap-6"> <Item variant="outline"> <ItemMedia variant="icon"><WalletIcon /></ItemMedia> <ItemContent> <ItemTitle>Phantom wallet</ItemTitle> <ItemDescription>7nXK...Qp2d, devnet</ItemDescription> </ItemContent> <ItemActions> <Button size="sm" variant="outline">Disconnect</Button> </ItemActions> </Item> <Item variant="muted" size="sm"> <ItemContent> <ItemTitle>Keeper is on</ItemTitle> <ItemDescription>Rebalances when drift exceeds 5%.</ItemDescription> </ItemContent> </Item> <ItemGroup> <Item as-child> <a href="#profile"> <ItemMedia variant="icon"><UserIcon /></ItemMedia> <ItemContent> <ItemTitle>Profile</ItemTitle> <ItemDescription>Name, avatar and bio</ItemDescription> </ItemContent> <ChevronRightIcon class="size-4 text-muted-foreground" /> </a> </Item> <ItemSeparator /> <Item as-child> <a href="#wallets"> <ItemMedia variant="icon"><WalletIcon /></ItemMedia> <ItemContent> <ItemTitle>Wallets</ItemTitle> <ItemDescription>2 connected</ItemDescription> </ItemContent> <ChevronRightIcon class="size-4 text-muted-foreground" /> </a> </Item> </ItemGroup> </div></template><script lang="ts"> import { Button } from "$lib/components/ui/button"; import * as Item from "$lib/components/ui/item"; import IconPlaceholder from "$lib/components/icon-placeholder/icon-placeholder.svelte";</script>
<div class="flex w-full max-w-md flex-col gap-6"> <Item.Root variant="outline"> <Item.Media variant="icon"><IconPlaceholder lucide="WalletIcon" tabler="IconWallet" hugeicons="WalletIcon" phosphor="WalletIcon" remixicon="RiWalletLine" /></Item.Media> <Item.Content> <Item.Title>Phantom wallet</Item.Title> <Item.Description>7nXK...Qp2d, devnet</Item.Description> </Item.Content> <Item.Actions> <Button size="sm" variant="outline">Disconnect</Button> </Item.Actions> </Item.Root> <Item.Root variant="muted" size="sm"> <Item.Content> <Item.Title>Keeper is on</Item.Title> <Item.Description>Rebalances when drift exceeds 5%.</Item.Description> </Item.Content> </Item.Root> <Item.Group> <Item.Root> {#snippet child({ props })} <a href="#profile" {...props}> <Item.Media variant="icon"><IconPlaceholder lucide="UserIcon" tabler="IconUser" hugeicons="UserIcon" phosphor="UserIcon" remixicon="RiUserLine" /></Item.Media> <Item.Content> <Item.Title>Profile</Item.Title> <Item.Description>Name, avatar and bio</Item.Description> </Item.Content> <IconPlaceholder lucide="ChevronRightIcon" tabler="IconChevronRight" hugeicons="ArrowRight01Icon" phosphor="CaretRightIcon" remixicon="RiArrowRightSLine" class="size-4 text-muted-foreground" /> </a> {/snippet} </Item.Root> <Item.Separator /> <Item.Root> {#snippet child({ props })} <a href="#wallets" {...props}> <Item.Media variant="icon"><IconPlaceholder lucide="WalletIcon" tabler="IconWallet" hugeicons="WalletIcon" phosphor="WalletIcon" remixicon="RiWalletLine" /></Item.Media> <Item.Content> <Item.Title>Wallets</Item.Title> <Item.Description>2 connected</Item.Description> </Item.Content> <IconPlaceholder lucide="ChevronRightIcon" tabler="IconChevronRight" hugeicons="ArrowRight01Icon" phosphor="CaretRightIcon" remixicon="RiArrowRightSLine" class="size-4 text-muted-foreground" /> </a> {/snippet} </Item.Root> </Item.Group></div>Installation
Section titled “Installation”npx shadcn@latest add @edmi-ui/itempnpm dlx shadcn@latest add @edmi-ui/itemyarn dlx shadcn@latest add @edmi-ui/itembunx shadcn@latest add @edmi-ui/itemPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Install the dependencies:
Terminal window npm install @base-ui/react class-variance-authorityTerminal window pnpm add @base-ui/react class-variance-authorityTerminal window yarn add @base-ui/react class-variance-authorityTerminal window bun add @base-ui/react class-variance-authorityAdd the Edmi components this one builds on:
separator.Copy the code from Component source into your project and update the import paths to match your aliases.
npx shadcn-vue@latest add @edmi-ui/itempnpm dlx shadcn-vue@latest add @edmi-ui/itemyarn dlx shadcn-vue@latest add @edmi-ui/itembunx shadcn-vue@latest add @edmi-ui/itemPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Install the dependencies:
Terminal window npm install reka-ui @vueuse/core class-variance-authorityTerminal window pnpm add reka-ui @vueuse/core class-variance-authorityTerminal window yarn add reka-ui @vueuse/core class-variance-authorityTerminal window bun add reka-ui @vueuse/core class-variance-authorityAdd the Edmi components this one builds on:
separator.Copy the code from Component source into your project and update the import paths to match your aliases.
npx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/item.jsonpnpm dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/item.jsonyarn dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/item.jsonbunx --bun shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/item.jsonPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Add the Edmi components this one builds on:
separator.Copy the code from Component source into your project and update the import paths to match your aliases.
import { Button } from "@/components/ui/button";import { Item, ItemActions, ItemContent, ItemDescription, ItemMedia, ItemTitle,} from "@/components/ui/item";
<div className="flex w-full max-w-md flex-col gap-6"> <Item variant="outline"> <ItemMedia variant="icon"> <WalletIcon /> </ItemMedia> <ItemContent> <ItemTitle>Phantom wallet</ItemTitle> <ItemDescription>7nXK...Qp2d, devnet</ItemDescription> </ItemContent> <ItemActions> <Button size="sm" variant="outline"> Disconnect </Button> </ItemActions> </Item> <Item variant="muted" size="sm"> <ItemContent> <ItemTitle>Keeper is on</ItemTitle> <ItemDescription>Rebalances when drift exceeds 5%.</ItemDescription> </ItemContent> </Item> {/* … */}</div><script setup lang="ts">import { Button } from "@/components/ui/button";import { Item, ItemActions, ItemContent, ItemDescription, ItemMedia, ItemTitle,} from "@/components/ui/item";</script>
<template> <div class="flex w-full max-w-md flex-col gap-6"> <Item variant="outline"> <ItemMedia variant="icon"><WalletIcon /></ItemMedia> <ItemContent> <ItemTitle>Phantom wallet</ItemTitle> <ItemDescription>7nXK...Qp2d, devnet</ItemDescription> </ItemContent> <ItemActions> <Button size="sm" variant="outline">Disconnect</Button> </ItemActions> </Item> <Item variant="muted" size="sm"> <ItemContent> <ItemTitle>Keeper is on</ItemTitle> <ItemDescription>Rebalances when drift exceeds 5%.</ItemDescription> </ItemContent> </Item> <!-- … --> </div></template><script lang="ts"> import * as Item from "$lib/components/ui/item"; import { Button } from "$lib/components/ui/button";</script>
<div class="flex w-full max-w-md flex-col gap-6"> <Item.Root variant="outline"> <Item.Media variant="icon"><WalletIcon /></Item.Media> <Item.Content> <Item.Title>Phantom wallet</Item.Title> <Item.Description>7nXK...Qp2d, devnet</Item.Description> </Item.Content> <Item.Actions> <Button size="sm" variant="outline">Disconnect</Button> </Item.Actions> </Item.Root> <Item.Root variant="muted" size="sm"> <Item.Content> <Item.Title>Keeper is on</Item.Title> <Item.Description>Rebalances when drift exceeds 5%.</Item.Description> </Item.Content> </Item.Root> <!-- … --></div>Component source
Section titled “Component source”import { mergeProps } from "@base-ui/react/merge-props";import { useRender } from "@base-ui/react/use-render";import { cva, type VariantProps } from "class-variance-authority";import { cn } from "cn";import type * as React from "react";
import { Separator } from "@/registry/edmi/ui/separator";
function ItemGroup({ className, ...props }: React.ComponentProps<"div">) { return ( // biome-ignore lint/a11y/useSemanticElements: stock anatomy keeps a div with role=list <div role="list" data-slot="item-group" className={cn( "group/item-group flex w-full flex-col gap-3 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2", className, )} {...props} /> );}
function ItemSeparator({ className, ...props}: React.ComponentProps<typeof Separator>) { return ( <Separator data-slot="item-separator" orientation="horizontal" className={cn("my-2", className)} {...props} /> );}
const itemVariants = cva( "group/item flex w-full flex-wrap items-center rounded-xl border text-sm transition-colors duration-100 outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring [a]:transition-colors [a]:hover:bg-accent", { variants: { variant: { default: "border-transparent", outline: "border-border bg-card", muted: "border-transparent bg-muted", }, size: { default: "gap-3.5 px-4 py-3.5", sm: "gap-2.5 px-3 py-2.5", xs: "gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0", }, }, defaultVariants: { variant: "default", size: "default", }, },);
function Item({ className, variant = "default", size = "default", render, ...props}: useRender.ComponentProps<"div"> & VariantProps<typeof itemVariants>) { return useRender({ defaultTagName: "div", props: mergeProps<"div">( { className: cn(itemVariants({ variant, size, className })), }, props, ), render, state: { slot: "item", variant, size, }, });}
const itemMediaVariants = cva( "flex shrink-0 items-center justify-center gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start [&_svg]:pointer-events-none", { variants: { variant: { default: "bg-transparent", icon: "size-[38px] rounded-[9px] border border-border bg-muted text-foreground group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 group-data-[size=xs]/item:rounded-md [&_svg:not([class*='size-'])]:size-4 group-data-[size=xs]/item:[&_svg:not([class*='size-'])]:size-3.5", image: "size-10 overflow-hidden rounded-[9px] group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover", }, }, defaultVariants: { variant: "default", }, },);
function ItemMedia({ className, variant = "default", ...props}: React.ComponentProps<"div"> & VariantProps<typeof itemMediaVariants>) { return ( <div data-slot="item-media" data-variant={variant} className={cn(itemMediaVariants({ variant, className }))} {...props} /> );}
function ItemContent({ className, ...props }: React.ComponentProps<"div">) { return ( <div data-slot="item-content" className={cn( "flex flex-1 flex-col gap-0.5 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none", className, )} {...props} /> );}
function ItemTitle({ className, ...props }: React.ComponentProps<"div">) { return ( <div data-slot="item-title" className={cn( "line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-semibold underline-offset-4", className, )} {...props} /> );}
function ItemDescription({ className, ...props }: React.ComponentProps<"p">) { return ( <p data-slot="item-description" className={cn( "line-clamp-2 text-left text-[12.5px] leading-normal font-normal text-muted-foreground group-data-[size=xs]/item:text-xs [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary", className, )} {...props} /> );}
function ItemActions({ className, ...props }: React.ComponentProps<"div">) { return ( <div data-slot="item-actions" className={cn("flex items-center gap-2", className)} {...props} /> );}
function ItemHeader({ className, ...props }: React.ComponentProps<"div">) { return ( <div data-slot="item-header" className={cn( "flex basis-full items-center justify-between gap-2", className, )} {...props} /> );}
function ItemFooter({ className, ...props }: React.ComponentProps<"div">) { return ( <div data-slot="item-footer" className={cn( "flex basis-full items-center justify-between gap-2", className, )} {...props} /> );}
export { Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle,};<script setup lang="ts">import type { PrimitiveProps } from 'reka-ui'import type { HTMLAttributes } from 'vue'import type { ItemVariants } from '.'import { Primitive } from 'reka-ui'import { cn } from '@/registry/edmi/lib/utils'import { itemVariants } from '.'
const props = withDefaults(defineProps<PrimitiveProps & { class?: HTMLAttributes['class'] variant?: ItemVariants['variant'] size?: ItemVariants['size']}>(), { as: 'div', variant: 'default', size: 'default',})</script>
<template> <Primitive data-slot="item" :data-variant="variant" :data-size="size" :as="as" :as-child="asChild" :class="cn(itemVariants({ variant, size }), props.class)" > <slot /> </Primitive></template><script setup lang="ts">import type { HTMLAttributes } from 'vue'import { cn } from '@/registry/edmi/lib/utils'
const props = defineProps<{ class?: HTMLAttributes['class']}>()</script>
<template> <div data-slot="item-actions" :class="cn('flex items-center gap-2', props.class)" > <slot /> </div></template><script setup lang="ts">import type { HTMLAttributes } from 'vue'import { cn } from '@/registry/edmi/lib/utils'
const props = defineProps<{ class?: HTMLAttributes['class']}>()</script>
<template> <div data-slot="item-content" :class="cn('flex flex-1 flex-col gap-0.5 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none', props.class)" > <slot /> </div></template><script setup lang="ts">import type { HTMLAttributes } from 'vue'import { cn } from '@/registry/edmi/lib/utils'
const props = defineProps<{ class?: HTMLAttributes['class']}>()</script>
<template> <p data-slot="item-description" :class="cn('line-clamp-2 text-left text-[12.5px] leading-normal font-normal text-muted-foreground group-data-[size=xs]/item:text-xs [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary', props.class)" > <slot /> </p></template><script setup lang="ts">import type { HTMLAttributes } from 'vue'import { cn } from '@/registry/edmi/lib/utils'
const props = defineProps<{ class?: HTMLAttributes['class']}>()</script>
<template> <div data-slot="item-footer" :class="cn('flex basis-full items-center justify-between gap-2', props.class)" > <slot /> </div></template><script setup lang="ts">import type { HTMLAttributes } from 'vue'import { cn } from '@/registry/edmi/lib/utils'
const props = defineProps<{ class?: HTMLAttributes['class']}>()</script>
<template> <div role="list" data-slot="item-group" :class="cn('group/item-group flex w-full flex-col gap-3 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2', props.class)" > <slot /> </div></template><script setup lang="ts">import type { HTMLAttributes } from 'vue'import { cn } from '@/registry/edmi/lib/utils'
const props = defineProps<{ class?: HTMLAttributes['class']}>()</script>
<template> <div data-slot="item-header" :class="cn('flex basis-full items-center justify-between gap-2', props.class)" > <slot /> </div></template><script setup lang="ts">import type { HTMLAttributes } from 'vue'import type { ItemMediaVariants } from '.'import { cn } from '@/registry/edmi/lib/utils'import { itemMediaVariants } from '.'
const props = withDefaults(defineProps<{ class?: HTMLAttributes['class'] variant?: ItemMediaVariants['variant']}>(), { variant: 'default',})</script>
<template> <div data-slot="item-media" :data-variant="variant" :class="cn(itemMediaVariants({ variant }), props.class)" > <slot /> </div></template><script setup lang="ts">import type { SeparatorProps } from 'reka-ui'import type { HTMLAttributes } from 'vue'import { reactiveOmit } from '@vueuse/core'import { cn } from '@/registry/edmi/lib/utils'import { Separator } from '@/registry/edmi/ui/separator'
const props = withDefaults(defineProps<SeparatorProps & { class?: HTMLAttributes['class'] }>(), { orientation: 'horizontal',})
const delegatedProps = reactiveOmit(props, 'class')</script>
<template> <Separator data-slot="item-separator" v-bind="delegatedProps" :class="cn('my-2', props.class)" /></template><script setup lang="ts">import type { HTMLAttributes } from 'vue'import { cn } from '@/registry/edmi/lib/utils'
const props = defineProps<{ class?: HTMLAttributes['class']}>()</script>
<template> <div data-slot="item-title" :class="cn('line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-semibold underline-offset-4', props.class)" > <slot /> </div></template>import type { VariantProps } from "class-variance-authority";import { cva } from "class-variance-authority";
export { default as Item } from "./Item.vue";export { default as ItemActions } from "./ItemActions.vue";export { default as ItemContent } from "./ItemContent.vue";export { default as ItemDescription } from "./ItemDescription.vue";export { default as ItemFooter } from "./ItemFooter.vue";export { default as ItemGroup } from "./ItemGroup.vue";export { default as ItemHeader } from "./ItemHeader.vue";export { default as ItemMedia } from "./ItemMedia.vue";export { default as ItemSeparator } from "./ItemSeparator.vue";export { default as ItemTitle } from "./ItemTitle.vue";
export const itemVariants = cva( "group/item flex w-full flex-wrap items-center rounded-xl border text-sm transition-colors duration-100 outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring [a]:transition-colors [a]:hover:bg-accent", { variants: { variant: { default: "border-transparent", outline: "border-border bg-card", muted: "border-transparent bg-muted", }, size: { default: "gap-3.5 px-4 py-3.5", sm: "gap-2.5 px-3 py-2.5", xs: "gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0", }, }, defaultVariants: { variant: "default", size: "default", }, },);export type ItemVariants = VariantProps<typeof itemVariants>;
export const itemMediaVariants = cva( "flex shrink-0 items-center justify-center gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start [&_svg]:pointer-events-none", { variants: { variant: { default: "bg-transparent", icon: "size-[38px] rounded-[9px] border border-border bg-muted text-foreground group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 group-data-[size=xs]/item:rounded-md [&_svg:not([class*=size-])]:size-4 group-data-[size=xs]/item:[&_svg:not([class*=size-])]:size-3.5", image: "size-10 overflow-hidden rounded-[9px] group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover", }, }, defaultVariants: { variant: "default", }, },);export type ItemMediaVariants = VariantProps<typeof itemMediaVariants>;<script lang="ts"> import { cn, type WithElementRef } from "$lib/utils.js"; import type { HTMLAttributes } from "svelte/elements";
let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();</script>
<div bind:this={ref} data-slot="item-actions" class={cn( "flex items-center gap-2", className )} {...restProps}> {@render children?.()}</div><script lang="ts"> import { cn, type WithElementRef } from "$lib/utils.js"; import type { HTMLAttributes } from "svelte/elements";
let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();</script>
<div bind:this={ref} data-slot="item-content" class={cn( "flex flex-1 flex-col gap-0.5 group-data-[size=xs]/item:gap-0 [&+[data-slot=item-content]]:flex-none", className )} {...restProps}> {@render children?.()}</div><script lang="ts"> import { cn, type WithElementRef } from "$lib/utils.js"; import type { HTMLAttributes } from "svelte/elements";
let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLAttributes<HTMLParagraphElement>> = $props();</script>
<p bind:this={ref} data-slot="item-description" class={cn( "line-clamp-2 text-left text-[12.5px] leading-normal font-normal text-muted-foreground group-data-[size=xs]/item:text-xs [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary", className )} {...restProps}> {@render children?.()}</p><script lang="ts"> import { cn, type WithElementRef } from "$lib/utils.js"; import type { HTMLAttributes } from "svelte/elements";
let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();</script>
<div bind:this={ref} data-slot="item-footer" class={cn( "flex basis-full items-center justify-between gap-2", className )} {...restProps}> {@render children?.()}</div><script lang="ts"> import { cn, type WithElementRef } from "$lib/utils.js"; import type { HTMLAttributes } from "svelte/elements";
let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();</script>
<div bind:this={ref} role="list" data-slot="item-group" class={cn( "group/item-group flex w-full flex-col gap-3 has-data-[size=sm]:gap-2.5 has-data-[size=xs]:gap-2", className )} {...restProps}> {@render children?.()}</div><script lang="ts"> import { cn, type WithElementRef } from "$lib/utils.js"; import type { HTMLAttributes } from "svelte/elements";
let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();</script>
<div bind:this={ref} data-slot="item-header" class={cn( "flex basis-full items-center justify-between gap-2", className )} {...restProps}> {@render children?.()}</div><script lang="ts" module> import { tv, type VariantProps } from "tailwind-variants";
export const itemMediaVariants = tv({ base: "flex shrink-0 items-center justify-center gap-2 group-has-data-[slot=item-description]/item:translate-y-0.5 group-has-data-[slot=item-description]/item:self-start [&_svg]:pointer-events-none", variants: { variant: { default: "bg-transparent", icon: "size-[38px] rounded-[9px] border border-border bg-muted text-foreground group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 group-data-[size=xs]/item:rounded-md [&_svg:not([class*='size-'])]:size-4 group-data-[size=xs]/item:[&_svg:not([class*='size-'])]:size-3.5", image: "size-10 overflow-hidden rounded-[9px] group-data-[size=sm]/item:size-8 group-data-[size=xs]/item:size-6 [&_img]:size-full [&_img]:object-cover", }, }, defaultVariants: { variant: "default", }, });
export type ItemMediaVariant = VariantProps<typeof itemMediaVariants>["variant"];</script>
<script lang="ts"> import { cn, type WithElementRef } from "$lib/utils.js"; import type { HTMLAttributes } from "svelte/elements";
let { ref = $bindable(null), class: className, children, variant = "default", ...restProps }: WithElementRef<HTMLAttributes<HTMLDivElement>> & { variant?: ItemMediaVariant } = $props();</script>
<div bind:this={ref} data-slot="item-media" data-variant={variant} class={cn(itemMediaVariants({ variant }), className)} {...restProps}> {@render children?.()}</div><script lang="ts"> import { Separator } from "$lib/registry/ui/separator/index.js"; import { cn } from "$lib/utils.js"; import type { ComponentProps } from "svelte";
let { ref = $bindable(null), class: className, ...restProps }: ComponentProps<typeof Separator> = $props();</script>
<Separator bind:ref data-slot="item-separator" orientation="horizontal" class={cn("my-2", className)} {...restProps}/><script lang="ts"> import { cn, type WithElementRef } from "$lib/utils.js"; import type { HTMLAttributes } from "svelte/elements";
let { ref = $bindable(null), class: className, children, ...restProps }: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();</script>
<div bind:this={ref} data-slot="item-title" class={cn( "line-clamp-1 flex w-fit items-center gap-2 text-sm leading-snug font-semibold underline-offset-4", className )} {...restProps}> {@render children?.()}</div><script lang="ts" module> import { tv, type VariantProps } from "tailwind-variants";
export const itemVariants = tv({ base: "group/item flex w-full flex-wrap items-center rounded-xl border text-sm transition-colors duration-100 outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring [a]:transition-colors [a]:hover:bg-accent", variants: { variant: { default: "border-transparent", outline: "border-border bg-card", muted: "border-transparent bg-muted", }, size: { default: "gap-3.5 px-4 py-3.5", sm: "gap-2.5 px-3 py-2.5", xs: "gap-2 px-2.5 py-2 in-data-[slot=dropdown-menu-content]:p-0", }, }, defaultVariants: { variant: "default", size: "default", }, });
export type ItemSize = VariantProps<typeof itemVariants>["size"]; export type ItemVariant = VariantProps<typeof itemVariants>["variant"];</script>
<script lang="ts"> import { cn, type WithElementRef } from "$lib/utils.js"; import type { Snippet } from "svelte"; import type { HTMLAttributes } from "svelte/elements";
let { ref = $bindable(null), class: className, child, variant = "default", size = "default", ...restProps }: WithElementRef<HTMLAttributes<HTMLDivElement>> & { child?: Snippet<[{ props: Record<string, unknown> }]>; variant?: ItemVariant; size?: ItemSize; } = $props();
const mergedProps = $derived({ class: cn(itemVariants({ variant, size }), className), "data-slot": "item", "data-variant": variant, "data-size": size, ...restProps, });</script>
{#if child} {@render child({ props: mergedProps })}{:else} <div bind:this={ref} {...mergedProps}> {@render mergedProps.children?.()} </div>{/if}import Root from "./item.svelte";import Actions from "./item-actions.svelte";import Content from "./item-content.svelte";import Description from "./item-description.svelte";import Footer from "./item-footer.svelte";import Group from "./item-group.svelte";import Header from "./item-header.svelte";import Media from "./item-media.svelte";import Separator from "./item-separator.svelte";import Title from "./item-title.svelte";
export { Actions, Actions as ItemActions, Content, Content as ItemContent, Description, Description as ItemDescription, Footer, Footer as ItemFooter, Group, Group as ItemGroup, Header, Header as ItemHeader, Media, Media as ItemMedia, Root, // Root as Item, Separator, Separator as ItemSeparator, Title, Title as ItemTitle,};| Prop | Type | Default |
|---|---|---|
Item variant |
default | outline | muted |
default |
Item size |
default | sm | xs |
default |
Item render |
ReactElement |
none (Base UI, replaces asChild) |
ItemMedia variant |
default | icon | image |
default |
Parts: ItemGroup, ItemSeparator, Item, ItemMedia, ItemContent, ItemTitle, ItemDescription, ItemActions, ItemHeader, ItemFooter.
✦ Edmi additions
Section titled “✦ Edmi additions”- Icon media is a bordered 38px tile on
--muted; outline items sit on--card.