Skip to content
edmi-ui

Item

Flexible row with media, title, description and actions. Variants default, outline, muted; sizes default, sm, xs.

StackBlitz ↗StackBlitz ↗StackBlitz ↗
Phantom wallet

7nXK...Qp2d, devnet

Keeper is on

Rebalances when drift exceeds 5%.

Phantom wallet

7nXK...Qp2d, devnet

Keeper is on

Rebalances when drift exceeds 5%.

Phantom wallet

7nXK...Qp2d, devnet

Keeper is on

Rebalances when drift exceeds 5%.

Terminal window
npx shadcn@latest add @edmi-ui/item
Terminal window
pnpm dlx shadcn@latest add @edmi-ui/item
Terminal window
yarn dlx shadcn@latest add @edmi-ui/item
Terminal window
bunx shadcn@latest add @edmi-ui/item

Pick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.

Terminal window
npx shadcn-vue@latest add @edmi-ui/item
Terminal window
pnpm dlx shadcn-vue@latest add @edmi-ui/item
Terminal window
yarn dlx shadcn-vue@latest add @edmi-ui/item
Terminal window
bunx shadcn-vue@latest add @edmi-ui/item

Pick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.

Terminal window
npx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/item.json
Terminal window
pnpm dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/item.json
Terminal window
yarn dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/item.json
Terminal window
bunx --bun shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/item.json

Pick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.

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>
registry/ui/item.tsx
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,
};
registry/ui/item/Item.vue
<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>
registry/ui/item/ItemActions.vue
<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>
registry/ui/item/ItemContent.vue
<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>
registry/ui/item/ItemDescription.vue
<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>
registry/ui/item/ItemFooter.vue
<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>
registry/ui/item/ItemGroup.vue
<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>
registry/ui/item/ItemHeader.vue
<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>
registry/ui/item/ItemMedia.vue
<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>
registry/ui/item/ItemSeparator.vue
<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>
registry/ui/item/ItemTitle.vue
<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>
registry/ui/item/index.ts
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>;
src/lib/registry/ui/item/item-actions.svelte
<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>
src/lib/registry/ui/item/item-content.svelte
<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>
src/lib/registry/ui/item/item-description.svelte
<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>
src/lib/registry/ui/item/item-footer.svelte
<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>
src/lib/registry/ui/item/item-group.svelte
<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>
src/lib/registry/ui/item/item-header.svelte
<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>
src/lib/registry/ui/item/item-media.svelte
<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>
src/lib/registry/ui/item/item-separator.svelte
<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}
/>
src/lib/registry/ui/item/item-title.svelte
<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>
src/lib/registry/ui/item/item.svelte
<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}
src/lib/registry/ui/item/index.ts
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.

  • Icon media is a bordered 38px tile on --muted; outline items sit on --card.