이 사이트는 shadcn-svelte 공식 문서의 한국어 번역입니다.
6.9k

Item

Previous Next

모든 콘텐츠를 표시하는 데 사용할 수 있는 다용도 컴포넌트입니다.

Item 컴포넌트는 거의 모든 유형의 콘텐츠를 담을 수 있는 간단한 플렉스 컨테이너입니다. 제목, 설명 및 액션을 표시하는 데 사용하세요. ItemGroup 컴포넌트와 함께 사용하여 아이템 목록을 만들 수 있습니다.

div 요소와 몇 가지 클래스로 동일한 결과를 얻을 수 있지만, 너무 많이 만들어서 컴포넌트로 만들기로 했습니다. 이제 항상 사용합니다.

기본 아이템

제목과 설명이 있는 간단한 아이템입니다.

프로필이 인증되었습니다.
<script lang="ts">
  import * as Item from "$lib/components/ui/item/index.js";
  import { Button } from "$lib/components/ui/button/index.js";
  import BadgeCheckIcon from "@lucide/svelte/icons/badge-check";
  import ChevronRightIcon from "@lucide/svelte/icons/chevron-right";
</script>
 
<div class="flex w-full max-w-md flex-col gap-6">
  <Item.Root variant="outline">
    <Item.Content>
      <Item.Title>기본 아이템</Item.Title>
      <Item.Description
        >제목과 설명이 있는 간단한 아이템입니다.</Item.Description
      >
    </Item.Content>
    <Item.Actions>
      <Button variant="outline" size="sm">작업</Button>
    </Item.Actions>
  </Item.Root>
  <Item.Root variant="outline" size="sm">
    {#snippet child({ props })}
      <a href="#/" {...props}>
        <Item.Media>
          <BadgeCheckIcon class="size-5" />
        </Item.Media>
        <Item.Content>
          <Item.Title>프로필이 인증되었습니다.</Item.Title>
        </Item.Content>
        <Item.Actions>
          <ChevronRightIcon class="size-4" />
        </Item.Actions>
      </a>
    {/snippet}
  </Item.Root>
</div>

설치

pnpm dlx shadcn-svelte@latest add item

사용법

<script lang="ts">
  import * as Item from "$lib/components/ui/item/index.js";
</script>
<Item.Root>
  <Item.Header>Item Header</Item.Header>
  <Item.Media />
  <Item.Content>
    <Item.Title>Item</Item.Title>
    <Item.Description>Item</Item.Description>
  </Item.Content>
  <Item.Actions />
  <Item.Footer>Item Footer</Item.Footer>
</Item.Root>

Item vs Field

체크박스, 입력, 라디오 또는 셀렉트와 같은 폼 입력을 표시해야 하는 경우 Field를 사용하세요.

제목, 설명 및 액션과 같은 콘텐츠만 표시하면 되는 경우 Item을 사용하세요.

예제

변형

기본 변형

은은한 배경과 테두리가 있는 표준 스타일입니다.

아웃라인 변형

명확한 테두리와 투명한 배경이 있는 아웃라인 스타일입니다.

뮤트 변형

보조 콘텐츠를 위한 절제된 색상의 차분한 외관입니다.

<script lang="ts">
  import * as Item from "$lib/components/ui/item/index.js";
  import { Button } from "$lib/components/ui/button/index.js";
</script>
 
<div class="flex flex-col gap-6">
  <Item.Root>
    <Item.Content>
      <Item.Title>기본 변형</Item.Title>
      <Item.Description
        >은은한 배경과 테두리가 있는 표준 스타일입니다.</Item.Description
      >
    </Item.Content>
    <Item.Actions>
      <Button variant="outline" size="sm">열기</Button>
    </Item.Actions>
  </Item.Root>
  <Item.Root variant="outline">
    <Item.Content>
      <Item.Title>아웃라인 변형</Item.Title>
      <Item.Description>
        명확한 테두리와 투명한 배경이 있는 아웃라인 스타일입니다.
      </Item.Description>
    </Item.Content>
    <Item.Actions>
      <Button variant="outline" size="sm">열기</Button>
    </Item.Actions>
  </Item.Root>
  <Item.Root variant="muted">
    <Item.Content>
      <Item.Title>뮤트 변형</Item.Title>
      <Item.Description
        >보조 콘텐츠를 위한 절제된 색상의 차분한 외관입니다.</Item.Description
      >
    </Item.Content>
    <Item.Actions>
      <Button variant="outline" size="sm">열기</Button>
    </Item.Actions>
  </Item.Root>
</div>

크기

Item 컴포넌트는 다양한 사용 사례에 맞는 여러 크기를 제공합니다. 예를 들어 컴팩트한 아이템에는 sm 크기를 사용하고 표준 아이템에는 기본 크기를 사용할 수 있습니다.

기본 아이템

제목과 설명이 있는 간단한 아이템입니다.

프로필이 인증되었습니다.
<script lang="ts">
  import * as Item from "$lib/components/ui/item/index.js";
  import { Button } from "$lib/components/ui/button/index.js";
  import BadgeCheckIcon from "@lucide/svelte/icons/badge-check";
  import ChevronRightIcon from "@lucide/svelte/icons/chevron-right";
</script>
 
<div class="flex w-full max-w-md flex-col gap-6">
  <Item.Root variant="outline">
    <Item.Content>
      <Item.Title>기본 아이템</Item.Title>
      <Item.Description
        >제목과 설명이 있는 간단한 아이템입니다.</Item.Description
      >
    </Item.Content>
    <Item.Actions>
      <Button variant="outline" size="sm">작업</Button>
    </Item.Actions>
  </Item.Root>
  <Item.Root variant="outline" size="sm">
    {#snippet child({ props })}
      <a href="#/" {...props}>
        <Item.Media>
          <BadgeCheckIcon class="size-5" />
        </Item.Media>
        <Item.Content>
          <Item.Title>프로필이 인증되었습니다.</Item.Title>
        </Item.Content>
        <Item.Actions>
          <ChevronRightIcon class="size-4" />
        </Item.Actions>
      </a>
    {/snippet}
  </Item.Root>
</div>

아이콘

보안 알림

알 수 없는 기기에서 새로운 로그인이 감지되었습니다.

<script lang="ts">
  import * as Item from "$lib/components/ui/item/index.js";
  import { Button } from "$lib/components/ui/button/index.js";
  import ShieldAlertIcon from "@lucide/svelte/icons/shield-alert";
</script>
 
<div class="flex w-full max-w-lg flex-col gap-6">
  <Item.Root variant="outline">
    <Item.Media variant="icon">
      <ShieldAlertIcon />
    </Item.Media>
    <Item.Content>
      <Item.Title>보안 알림</Item.Title>
      <Item.Description
        >알 수 없는 기기에서 새로운 로그인이 감지되었습니다.</Item.Description
      >
    </Item.Content>
    <Item.Actions>
      <Button size="sm" variant="outline">확인</Button>
    </Item.Actions>
  </Item.Root>
</div>

아바타

ER
Evil Rabbit

5개월 전 마지막 접속

ER
팀 멤버 없음

이 프로젝트에서 협업할 팀을 초대하세요.

<script lang="ts">
  import * as Item from "$lib/components/ui/item/index.js";
  import * as Avatar from "$lib/components/ui/avatar/index.js";
  import { Button } from "$lib/components/ui/button/index.js";
  import Plus from "@lucide/svelte/icons/plus";
</script>
 
<div class="flex w-full max-w-lg flex-col gap-6">
  <Item.Root variant="outline">
    <Item.Media>
      <Avatar.Root class="size-10">
        <Avatar.Image src="https://github.com/evilrabbit.png" />
        <Avatar.Fallback>ER</Avatar.Fallback>
      </Avatar.Root>
    </Item.Media>
    <Item.Content>
      <Item.Title>Evil Rabbit</Item.Title>
      <Item.Description>5개월 전 마지막 접속</Item.Description>
    </Item.Content>
    <Item.Actions>
      <Button
        size="icon"
        variant="outline"
        class="rounded-full"
        aria-label="초대"
      >
        <Plus />
      </Button>
    </Item.Actions>
  </Item.Root>
  <Item.Root variant="outline">
    <Item.Media>
      <div
        class="*:data-[slot=avatar]:ring-background flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:grayscale"
      >
        <Avatar.Root class="hidden sm:flex">
          <Avatar.Image src="https://github.com/shadcn.png" alt="@shadcn" />
          <Avatar.Fallback>CN</Avatar.Fallback>
        </Avatar.Root>
        <Avatar.Root class="hidden sm:flex">
          <Avatar.Image
            src="https://github.com/maxleiter.png"
            alt="@maxleiter"
          />
          <Avatar.Fallback>LR</Avatar.Fallback>
        </Avatar.Root>
        <Avatar.Root>
          <Avatar.Image
            src="https://github.com/evilrabbit.png"
            alt="@evilrabbit"
          />
          <Avatar.Fallback>ER</Avatar.Fallback>
        </Avatar.Root>
      </div>
    </Item.Media>
    <Item.Content>
      <Item.Title>팀 멤버 없음</Item.Title>
      <Item.Description
        >이 프로젝트에서 협업할 팀을 초대하세요.</Item.Description
      >
    </Item.Content>
    <Item.Actions>
      <Button size="sm" variant="outline">초대</Button>
    </Item.Actions>
  </Item.Root>
</div>

이미지

<script lang="ts">
  import * as Item from "$lib/components/ui/item/index.js";
 
  const music = [
    {
      title: "한밤의 도시 불빛",
      artist: "네온 드림스",
      album: "일렉트릭 나이츠",
      duration: "3:45"
    },
    {
      title: "커피숍 대화",
      artist: "더 모닝 브루",
      album: "도시 이야기",
      duration: "4:05"
    },
    {
      title: "디지털 레인",
      artist: "사이버 심포니",
      album: "바이너리 비트",
      duration: "3:30"
    }
  ];
</script>
 
<div class="flex w-full max-w-md flex-col gap-6">
  <div class="flex w-full max-w-md flex-col gap-4">
    {#each music as song (song)}
      <Item.Root variant="outline">
        {#snippet child({ props })}
          <a href="#/" {...props}>
            <Item.Media variant="image">
              <img
                src={`https://avatar.vercel.sh/${song.title}`}
                alt={song.title}
                width="32"
                height="32"
                class="size-8 rounded object-cover grayscale"
              />
            </Item.Media>
            <Item.Content>
              <Item.Title class="line-clamp-1">
                {song.title} -
                <span class="text-muted-foreground">{song.album}</span>
              </Item.Title>
              <Item.Description>{song.artist}</Item.Description>
            </Item.Content>
            <Item.Content class="flex-none text-center">
              <Item.Description>{song.duration}</Item.Description>
            </Item.Content>
          </a>
        {/snippet}
      </Item.Root>
    {/each}
  </div>
</div>

그룹

s
shadcn

shadcn@vercel.com

m
maxleiter

maxleiter@vercel.com

e
evilrabbit

evilrabbit@vercel.com

<script lang="ts">
  import * as Item from "$lib/components/ui/item/index.js";
  import * as Avatar from "$lib/components/ui/avatar/index.js";
  import { Button } from "$lib/components/ui/button/index.js";
  import Plus from "@lucide/svelte/icons/plus";
 
  const people = [
    {
      username: "shadcn",
      avatar: "https://github.com/shadcn.png",
      email: "shadcn@vercel.com"
    },
    {
      username: "maxleiter",
      avatar: "https://github.com/maxleiter.png",
      email: "maxleiter@vercel.com"
    },
    {
      username: "evilrabbit",
      avatar: "https://github.com/evilrabbit.png",
      email: "evilrabbit@vercel.com"
    }
  ];
</script>
 
<div class="flex w-full max-w-md flex-col gap-6">
  <Item.Group>
    {#each people as person, index (person.username)}
      <Item.Root>
        <Item.Media>
          <Avatar.Root>
            <Avatar.Image src={person.avatar} class="grayscale" />
            <Avatar.Fallback>{person.username.charAt(0)}</Avatar.Fallback>
          </Avatar.Root>
        </Item.Media>
        <Item.Content class="gap-1">
          <Item.Title>{person.username}</Item.Title>
          <Item.Description>{person.email}</Item.Description>
        </Item.Content>
        <Item.Actions>
          <Button variant="ghost" size="icon" class="rounded-full">
            <Plus />
          </Button>
        </Item.Actions>
      </Item.Root>
      {#if index !== people.length - 1}
        <Item.Separator />
      {/if}
    {/each}
  </Item.Group>
</div>

헤더

v0-1.5-sm
v0-1.5-sm

일상적인 작업 및 UI 생성.

v0-1.5-lg
v0-1.5-lg

고급 사고 또는 추론.

v0-2.0-mini
v0-2.0-mini

모두를 위한 오픈 소스 모델.

<script lang="ts">
  import * as Item from "$lib/components/ui/item/index.js";
 
  const models = [
    {
      name: "v0-1.5-sm",
      description: "일상적인 작업 및 UI 생성.",
      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: "고급 사고 또는 추론.",
      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: "모두를 위한 오픈 소스 모델.",
      image:
        "https://images.unsplash.com/photo-1602146057681-08560aee8cde?q=80&w=640&auto=format&fit=crop",
      credit: "Cherry Laithang on Unsplash"
    }
  ];
</script>
 
<div class="flex w-full max-w-xl flex-col gap-6">
  <Item.Group class="grid grid-cols-3 gap-4">
    {#each models as model (model.name)}
      <Item.Root variant="outline">
        <Item.Header>
          <img
            src={model.image}
            alt={model.name}
            width="128"
            height="128"
            class="aspect-square w-full rounded-sm object-cover"
          />
        </Item.Header>
        <Item.Content>
          <Item.Title>{model.name}</Item.Title>
          <Item.Description>{model.description}</Item.Description>
        </Item.Content>
      </Item.Root>
    {/each}
  </Item.Group>
</div>

링크

아이템을 링크로 렌더링하려면 child 스니펫을 사용하세요. 호버 및 포커스 상태가 앵커 요소에 적용됩니다.

<script lang="ts">
  import * as Item from "$lib/components/ui/item/index.js";
  import ChevronRightIcon from "@lucide/svelte/icons/chevron-right";
  import ExternalLinkIcon from "@lucide/svelte/icons/external-link";
</script>
 
<div class="flex w-full max-w-md flex-col gap-4">
  <Item.Root>
    {#snippet child({ props })}
      <a href="#/" {...props}>
        <Item.Content>
          <Item.Title>문서 방문하기</Item.Title>
          <Item.Description>컴포넌트 시작 방법을 알아보세요.</Item.Description>
        </Item.Content>
        <Item.Actions>
          <ChevronRightIcon class="size-4" />
        </Item.Actions>
      </a>
    {/snippet}
  </Item.Root>
  <Item.Root variant="outline">
    {#snippet child({ props })}
      <a href="#/" target="_blank" rel="noopener noreferrer" {...props}>
        <Item.Content>
          <Item.Title>외부 리소스</Item.Title>
          <Item.Description
            >보안 속성과 함께 새 탭에서 열립니다.</Item.Description
          >
        </Item.Content>
        <Item.Actions>
          <ExternalLinkIcon class="size-4" />
        </Item.Actions>
      </a>
    {/snippet}
  </Item.Root>
</div>

드롭다운

<script lang="ts">
  import * as Item from "$lib/components/ui/item/index.js";
  import * as Avatar from "$lib/components/ui/avatar/index.js";
  import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js";
  import { Button } from "$lib/components/ui/button/index.js";
  import ChevronDown from "@lucide/svelte/icons/chevron-down";
 
  const people = [
    {
      username: "shadcn",
      avatar: "https://github.com/shadcn.png",
      email: "shadcn@vercel.com"
    },
    {
      username: "maxleiter",
      avatar: "https://github.com/maxleiter.png",
      email: "maxleiter@vercel.com"
    },
    {
      username: "evilrabbit",
      avatar: "https://github.com/evilrabbit.png",
      email: "evilrabbit@vercel.com"
    }
  ];
</script>
 
<div class="flex min-h-64 w-full max-w-md flex-col items-center gap-6">
  <DropdownMenu.Root>
    <DropdownMenu.Trigger>
      {#snippet child({ props })}
        <Button {...props} variant="outline" size="sm" class="w-fit">
          선택 <ChevronDown />
        </Button>
      {/snippet}
    </DropdownMenu.Trigger>
    <DropdownMenu.Content class="w-72 [--radius:0.65rem]" align="end">
      {#each people as person (person.username)}
        <DropdownMenu.Item class="p-0">
          <Item.Root size="sm" class="w-full p-2">
            <Item.Media>
              <Avatar.Root class="size-8">
                <Avatar.Image src={person.avatar} class="grayscale" />
                <Avatar.Fallback>{person.username.charAt(0)}</Avatar.Fallback>
              </Avatar.Root>
            </Item.Media>
            <Item.Content class="gap-0.5">
              <Item.Title>{person.username}</Item.Title>
              <Item.Description>{person.email}</Item.Description>
            </Item.Content>
          </Item.Root>
        </DropdownMenu.Item>
      {/each}
    </DropdownMenu.Content>
  </DropdownMenu.Root>
</div>