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

Field

Previous Next

라벨, 컨트롤, 도움말 텍스트를 결합하여 접근 가능한 폼 필드와 그룹화된 입력을 구성합니다.

결제 수단

모든 거래는 안전하게 암호화됩니다

16자리 번호를 입력하세요.

청구 주소

결제 수단과 연결된 청구 주소

<script lang="ts">
  import { Button } from "$lib/components/ui/button/index.js";
  import { Checkbox } from "$lib/components/ui/checkbox/index.js";
  import * as Field from "$lib/components/ui/field/index.js";
  import { Input } from "$lib/components/ui/input/index.js";
  import * as Select from "$lib/components/ui/select/index.js";
  import { Textarea } from "$lib/components/ui/textarea/index.js";
 
  let month = $state<string>();
  let year = $state<string>();
</script>
 
<div class="w-full max-w-md">
  <form>
    <Field.Group>
      <Field.Set>
        <Field.Legend>결제 수단</Field.Legend>
        <Field.Description>모든 거래는 안전하게 암호화됩니다</Field.Description>
        <Field.Group>
          <Field.Field>
            <Field.Label for="checkout-7j9-card-name-43j"
              >카드 소유자 이름</Field.Label
            >
            <Input
              id="checkout-7j9-card-name-43j"
              placeholder="홍길동"
              required
            />
          </Field.Field>
          <div class="grid grid-cols-3 gap-4">
            <Field.Field class="col-span-2">
              <Field.Label for="checkout-7j9-card-number-uw1"
                >카드 번호</Field.Label
              >
              <Input
                id="checkout-7j9-card-number-uw1"
                placeholder="1234 5678 9012 3456"
                required
              />
              <Field.Description>16자리 번호를 입력하세요.</Field.Description>
            </Field.Field>
            <Field.Field class="col-span-1">
              <Field.Label for="checkout-7j9-cvv">CVV</Field.Label>
              <Input id="checkout-7j9-cvv" placeholder="123" required />
            </Field.Field>
          </div>
          <div class="grid grid-cols-2 gap-4">
            <Field.Field>
              <Field.Label for="checkout-7j9-exp-month-ts6">월</Field.Label>
              <Select.Root type="single" bind:value={month}>
                <Select.Trigger id="checkout-7j9-exp-month-ts6">
                  <span>
                    {month || "MM"}
                  </span>
                </Select.Trigger>
                <Select.Content>
                  <Select.Item value="01">01</Select.Item>
                  <Select.Item value="02">02</Select.Item>
                  <Select.Item value="03">03</Select.Item>
                  <Select.Item value="04">04</Select.Item>
                  <Select.Item value="05">05</Select.Item>
                  <Select.Item value="06">06</Select.Item>
                  <Select.Item value="07">07</Select.Item>
                  <Select.Item value="08">08</Select.Item>
                  <Select.Item value="09">09</Select.Item>
                  <Select.Item value="10">10</Select.Item>
                  <Select.Item value="11">11</Select.Item>
                  <Select.Item value="12">12</Select.Item>
                </Select.Content>
              </Select.Root>
            </Field.Field>
            <Field.Field>
              <Field.Label for="checkout-7j9-exp-year-f59">연도</Field.Label>
              <Select.Root type="single" bind:value={year}>
                <Select.Trigger id="checkout-7j9-exp-year-f59">
                  <span>
                    {year || "YYYY"}
                  </span>
                </Select.Trigger>
                <Select.Content>
                  <Select.Item value="2024">2024</Select.Item>
                  <Select.Item value="2025">2025</Select.Item>
                  <Select.Item value="2026">2026</Select.Item>
                  <Select.Item value="2027">2027</Select.Item>
                  <Select.Item value="2028">2028</Select.Item>
                  <Select.Item value="2029">2029</Select.Item>
                </Select.Content>
              </Select.Root>
            </Field.Field>
          </div>
        </Field.Group>
      </Field.Set>
      <Field.Separator />
      <Field.Set>
        <Field.Legend>청구 주소</Field.Legend>
        <Field.Description>결제 수단과 연결된 청구 주소</Field.Description>
        <Field.Group>
          <Field.Field orientation="horizontal">
            <Checkbox id="checkout-7j9-same-as-shipping-wgm" checked={true} />
            <Field.Label
              for="checkout-7j9-same-as-shipping-wgm"
              class="font-normal"
            >
              배송 주소와 동일
            </Field.Label>
          </Field.Field>
        </Field.Group>
      </Field.Set>
      <Field.Separator />
      <Field.Set>
        <Field.Group>
          <Field.Field>
            <Field.Label for="checkout-7j9-optional-comments"
              >코멘트</Field.Label
            >
            <Textarea
              id="checkout-7j9-optional-comments"
              placeholder="추가 코멘트를 입력하세요"
              class="resize-none"
            />
          </Field.Field>
        </Field.Group>
      </Field.Set>
      <Field.Field orientation="horizontal">
        <Button type="submit">제출</Button>
        <Button variant="outline" type="button">취소</Button>
      </Field.Field>
    </Field.Group>
  </form>
</div>

설치

pnpm dlx shadcn-svelte@latest add field

사용법

<script lang="ts">
  import * as Field from "$lib/components/ui/field/index.js";
</script>
<Field.Set>
  <Field.Legend>프로필</Field.Legend>
  <Field.Description>인보이스 및 이메일에 표시됩니다.</Field.Description>
  <Field.Group>
    <Field.Field>
      <Field.Label for="name">전체 이름</Field.Label>
      <Input id="name" autoComplete="off" placeholder="홍길동" />
      <Field.Description>인보이스 및 이메일에 표시됩니다.</Field.Description>
    </Field.Field>
    <Field.Field>
      <Field.Label for="username">사용자 이름</Field.Label>
      <Input id="username" autoComplete="off" aria-invalid />
      <Field.Error>다른 사용자 이름을 선택하세요.</Field.Error>
    </Field.Field>
    <Field.Field orientation="horizontal">
      <Switch id="newsletter" />
      <Field.Label for="newsletter">뉴스레터 구독</Field.Label>
    </Field.Field>
  </Field.Group>
</Field.Set>

구조

Field 패밀리는 접근 가능한 폼을 구성하기 위해 설계되었습니다. 일반적인 필드 구조는 다음과 같습니다:

<Field.Field>
  <Field.Label for="input-id">라벨</Field.Label>
  <!-- Input, Select, Switch, etc. -->
  <Field.Description>선택적 도움말 텍스트.</Field.Description>
  <Field.Error>유효성 검사 메시지.</Field.Error>
</Field.Field>
  • Field.Field는 단일 필드의 핵심 래퍼입니다.
  • Field.Content는 라벨과 설명을 그룹화하는 플렉스 컬럼입니다. 설명이 없으면 필수가 아닙니다.
  • 관련 필드는 Field.Group으로 감싸고, 의미론적 그룹화를 위해 Field.SetField.Legend를 사용하세요.

예제

Input

계정의 고유한 사용자명을 선택하세요.

최소 8자 이상이어야 합니다.

<script lang="ts">
  import * as Field from "$lib/components/ui/field/index.js";
  import { Input } from "$lib/components/ui/input/index.js";
</script>
 
<div class="w-full max-w-md">
  <Field.Set>
    <Field.Group>
      <Field.Field>
        <Field.Label for="username">사용자명</Field.Label>
        <Input id="username" type="text" placeholder="홍길동" />
        <Field.Description
          >계정의 고유한 사용자명을 선택하세요.</Field.Description
        >
      </Field.Field>
      <Field.Field>
        <Field.Label for="password">비밀번호</Field.Label>
        <Field.Description>최소 8자 이상이어야 합니다.</Field.Description>
        <Input id="password" type="password" placeholder="••••••••" />
      </Field.Field>
    </Field.Group>
  </Field.Set>
</div>

Textarea

서비스에 대한 의견을 공유해 주세요.

<script lang="ts">
  import * as Field from "$lib/components/ui/field/index.js";
  import { Textarea } from "$lib/components/ui/textarea/index.js";
</script>
 
<div class="w-full max-w-md">
  <Field.Set>
    <Field.Group>
      <Field.Field>
        <Field.Label for="feedback">피드백</Field.Label>
        <Textarea
          id="feedback"
          placeholder="여러분의 피드백은 개선에 도움이 됩니다..."
          rows={4}
        />
        <Field.Description
          >서비스에 대한 의견을 공유해 주세요.</Field.Description
        >
      </Field.Field>
    </Field.Group>
  </Field.Set>
</div>

Select

부서 또는 업무 영역을 선택하세요.

<script lang="ts">
  import * as Field from "$lib/components/ui/field/index.js";
  import * as Select from "$lib/components/ui/select/index.js";
 
  let department = $state<string>();
 
  const departments = [
    { value: "engineering", label: "Engineering" },
    { value: "design", label: "Design" },
    { value: "marketing", label: "Marketing" },
    { value: "sales", label: "Sales" },
    { value: "support", label: "Customer Support" },
    { value: "hr", label: "Human Resources" },
    { value: "finance", label: "Finance" },
    { value: "operations", label: "Operations" }
  ];
 
  const departmentLabel = $derived(
    departments.find((d) => d.value === department)?.label ?? "부서 선택"
  );
</script>
 
<div class="w-full max-w-md">
  <Field.Field>
    <Field.Label for="department">부서</Field.Label>
    <Select.Root type="single" bind:value={department}>
      <Select.Trigger id="department">
        {departmentLabel}
      </Select.Trigger>
      <Select.Content>
        {#each departments as department (department.value)}
          <Select.Item {...department} />
        {/each}
      </Select.Content>
    </Select.Root>
    <Field.Description>부서 또는 업무 영역을 선택하세요.</Field.Description>
  </Field.Field>
</div>

Slider

예산 범위를 설정하세요 ($200 - 800).

<script lang="ts">
  import * as Field from "$lib/components/ui/field/index.js";
  import { Slider } from "$lib/components/ui/slider/index.js";
 
  let value = $state([200, 800]);
</script>
 
<div class="w-full max-w-md">
  <Field.Field>
    <Field.Label>가격 범위</Field.Label>
    <Field.Description>
      예산 범위를 설정하세요 ($<span class="font-medium tabular-nums"
        >{value[0]}</span
      >
      -
      <span class="font-medium tabular-nums">{value[1]}</span>).
    </Field.Description>
    <Slider
      type="multiple"
      bind:value
      max={1000}
      min={0}
      step={10}
      class="mt-2 w-full"
      aria-label="Price Range"
    />
  </Field.Field>
</div>

Fieldset

주소 정보

주문을 배송하기 위해 주소가 필요합니다.

<script lang="ts">
  import * as Field from "$lib/components/ui/field/index.js";
  import { Input } from "$lib/components/ui/input/index.js";
</script>
 
<div class="w-full max-w-md space-y-6">
  <Field.Set>
    <Field.Legend>주소 정보</Field.Legend>
    <Field.Description
      >주문을 배송하기 위해 주소가 필요합니다.</Field.Description
    >
    <Field.Group>
      <Field.Field>
        <Field.Label for="street">도로명 주소</Field.Label>
        <Input
          id="street"
          type="text"
          placeholder="서울시 강남구 테헤란로 123"
        />
      </Field.Field>
      <div class="grid grid-cols-2 gap-4">
        <Field.Field>
          <Field.Label for="city">도시</Field.Label>
          <Input id="city" type="text" placeholder="서울" />
        </Field.Field>
        <Field.Field>
          <Field.Label for="zip">우편번호</Field.Label>
          <Input id="zip" type="text" placeholder="06234" />
        </Field.Field>
      </div>
    </Field.Group>
  </Field.Set>
</div>

Checkbox

데스크톱에 표시할 항목

데스크톱에 표시할 항목을 선택하세요.

데스크톱 및 문서 폴더가 iCloud Drive와 동기화됩니다. 다른 기기에서 액세스할 수 있습니다.

<script lang="ts">
  import * as Field from "$lib/components/ui/field/index.js";
  import { Checkbox } from "$lib/components/ui/checkbox/index.js";
</script>
 
<div class="w-full max-w-md">
  <Field.Group>
    <Field.Set>
      <Field.Legend variant="label">데스크톱에 표시할 항목</Field.Legend>
      <Field.Description>데스크톱에 표시할 항목을 선택하세요.</Field.Description
      >
      <Field.Group class="gap-3">
        <Field.Field orientation="horizontal">
          <Checkbox id="finder-pref-9k2-hard-disks-ljj" checked />
          <Field.Label for="finder-pref-9k2-hard-disks-ljj" class="font-normal">
            하드 디스크
          </Field.Label>
        </Field.Field>
        <Field.Field orientation="horizontal">
          <Checkbox id="finder-pref-9k2-external-disks-1yg" />
          <Field.Label
            for="finder-pref-9k2-external-disks-1yg"
            class="font-normal"
          >
            외장 디스크
          </Field.Label>
        </Field.Field>
        <Field.Field orientation="horizontal">
          <Checkbox id="finder-pref-9k2-cds-dvds-fzt" />
          <Field.Label for="finder-pref-9k2-cds-dvds-fzt" class="font-normal">
            CD, DVD 및 iPod
          </Field.Label>
        </Field.Field>
        <Field.Field orientation="horizontal">
          <Checkbox id="finder-pref-9k2-connected-servers-6l2" />
          <Field.Label
            for="finder-pref-9k2-connected-servers-6l2"
            class="font-normal"
          >
            연결된 서버
          </Field.Label>
        </Field.Field>
      </Field.Group>
    </Field.Set>
    <Field.Separator />
    <Field.Field orientation="horizontal">
      <Checkbox id="finder-pref-9k2-sync-folders-nep" checked />
      <Field.Content>
        <Field.Label for="finder-pref-9k2-sync-folders-nep">
          데스크톱 및 문서 폴더 동기화
        </Field.Label>
        <Field.Description>
          데스크톱 및 문서 폴더가 iCloud Drive와 동기화됩니다. 다른 기기에서
          액세스할 수 있습니다.
        </Field.Description>
      </Field.Content>
    </Field.Field>
  </Field.Group>
</div>

Radio

연간 및 평생 플랜은 상당한 할인을 제공합니다.

<script lang="ts">
  import * as Field from "$lib/components/ui/field/index.js";
  import * as RadioGroup from "$lib/components/ui/radio-group/index.js";
 
  let plan = $state("monthly");
</script>
 
<div class="w-full max-w-md">
  <Field.Set>
    <Field.Label>구독 플랜</Field.Label>
    <Field.Description
      >연간 및 평생 플랜은 상당한 할인을 제공합니다.</Field.Description
    >
    <RadioGroup.Root bind:value={plan}>
      <Field.Field orientation="horizontal">
        <RadioGroup.Item value="monthly" id="plan-monthly" />
        <Field.Label for="plan-monthly" class="font-normal"
          >월간 ($9.99/월)</Field.Label
        >
      </Field.Field>
      <Field.Field orientation="horizontal">
        <RadioGroup.Item value="yearly" id="plan-yearly" />
        <Field.Label for="plan-yearly" class="font-normal"
          >연간 ($99.99/년)</Field.Label
        >
      </Field.Field>
      <Field.Field orientation="horizontal">
        <RadioGroup.Item value="lifetime" id="plan-lifetime" />
        <Field.Label for="plan-lifetime" class="font-normal"
          >평생 ($299.99)</Field.Label
        >
      </Field.Field>
    </RadioGroup.Root>
  </Field.Set>
</div>

Switch

다중 인증을 활성화합니다. 2단계 인증 기기가 없는 경우 이메일로 전송된 일회용 코드를 사용할 수 있습니다.

<script lang="ts">
  import * as Field from "$lib/components/ui/field/index.js";
  import { Switch } from "$lib/components/ui/switch/index.js";
</script>
 
<div class="w-full max-w-md">
  <Field.Field orientation="horizontal">
    <Field.Content>
      <Field.Label for="2fa">다중 인증</Field.Label>
      <Field.Description>
        다중 인증을 활성화합니다. 2단계 인증 기기가 없는 경우 이메일로 전송된
        일회용 코드를 사용할 수 있습니다.
      </Field.Description>
    </Field.Content>
    <Switch id="2fa" />
  </Field.Field>
</div>

Choice Card

선택 가능한 필드 그룹을 만들려면 Field 컴포넌트를 FieldLabel 안에 감싸세요. 이는 RadioItem, Checkbox, Switch 컴포넌트와 함께 작동합니다.

클러스터의 컴퓨팅 환경을 선택하세요.

<script lang="ts">
  import * as Field from "$lib/components/ui/field/index.js";
  import * as RadioGroup from "$lib/components/ui/radio-group/index.js";
 
  let computeEnvironment = $state("kubernetes");
</script>
 
<div class="w-full max-w-md">
  <Field.Group>
    <Field.Set>
      <Field.Label for="compute-environment-p8w">컴퓨팅 환경</Field.Label>
      <Field.Description>클러스터의 컴퓨팅 환경을 선택하세요.</Field.Description
      >
      <RadioGroup.Root bind:value={computeEnvironment}>
        <Field.Label for="kubernetes-r2h">
          <Field.Field orientation="horizontal">
            <Field.Content>
              <Field.Title>Kubernetes</Field.Title>
              <Field.Description>
                K8s로 구성된 클러스터에서 GPU 워크로드를 실행합니다.
              </Field.Description>
            </Field.Content>
            <RadioGroup.Item value="kubernetes" id="kubernetes-r2h" />
          </Field.Field>
        </Field.Label>
        <Field.Label for="vm-z4k">
          <Field.Field orientation="horizontal">
            <Field.Content>
              <Field.Title>가상 머신</Field.Title>
              <Field.Description>
                VM으로 구성된 클러스터에 액세스하여 GPU 워크로드를 실행합니다.
              </Field.Description>
            </Field.Content>
            <RadioGroup.Item value="vm" id="vm-z4k" />
          </Field.Field>
        </Field.Label>
      </RadioGroup.Root>
    </Field.Set>
  </Field.Group>
</div>

Field Group

Field.Group으로 Field 컴포넌트를 쌓으세요. 분할하려면 Field.Separator를 추가하세요.

연구나 이미지 생성과 같이 시간이 걸리는 요청에 ChatGPT가 응답하면 알림을 받습니다.

생성한 작업에 업데이트가 있을 때 알림을 받습니다. 작업 관리

<script lang="ts">
  import * as Field from "$lib/components/ui/field/index.js";
  import { Checkbox } from "$lib/components/ui/checkbox/index.js";
</script>
 
<div class="w-full max-w-md">
  <Field.Group>
    <Field.Set>
      <Field.Label>응답</Field.Label>
      <Field.Description>
        연구나 이미지 생성과 같이 시간이 걸리는 요청에 ChatGPT가 응답하면 알림을
        받습니다.
      </Field.Description>
      <Field.Group data-slot="checkbox-group">
        <Field.Field orientation="horizontal">
          <Checkbox id="push" checked disabled />
          <Field.Label for="push" class="font-normal">푸시 알림</Field.Label>
        </Field.Field>
      </Field.Group>
    </Field.Set>
    <Field.Separator />
    <Field.Set>
      <Field.Label>작업</Field.Label>
      <Field.Description>
        생성한 작업에 업데이트가 있을 때 알림을 받습니다.
        <a href="#/">작업 관리</a>
      </Field.Description>
      <Field.Group data-slot="checkbox-group">
        <Field.Field orientation="horizontal">
          <Checkbox id="push-tasks" />
          <Field.Label for="push-tasks" class="font-normal"
            >푸시 알림</Field.Label
          >
        </Field.Field>
        <Field.Field orientation="horizontal">
          <Checkbox id="email-tasks" />
          <Field.Label for="email-tasks" class="font-normal"
            >이메일 알림</Field.Label
          >
        </Field.Field>
      </Field.Group>
    </Field.Set>
  </Field.Group>
</div>

Responsive Layout

  • 수직 필드: 기본 방향은 라벨, 컨트롤, 도움말 텍스트를 쌓습니다. 모바일 우선 레이아웃에 이상적입니다.
  • 수평 필드: Fieldorientation="horizontal"을 설정하여 라벨과 컨트롤을 나란히 정렬합니다. 설명을 정렬 상태로 유지하려면 Field.Content와 함께 사용하세요.
  • 반응형 필드: 컨테이너 인식 부모 내에서 자동 컬럼 레이아웃을 위해 orientation="responsive"를 설정합니다. 특정 중단점에서 방향을 전환하려면 Field.Group@container/field-group 클래스를 적용하세요.
프로필

프로필 정보를 입력하세요.

신원 확인을 위해 전체 이름을 입력하세요

여기에 메시지를 작성할 수 있습니다. 짧게 작성하는 것이 좋으며, 100자 이내로 작성하세요.

<script lang="ts">
  import * as Field from "$lib/components/ui/field/index.js";
  import { Button } from "$lib/components/ui/button/index.js";
  import { Input } from "$lib/components/ui/input/index.js";
  import { Textarea } from "$lib/components/ui/textarea/index.js";
</script>
 
<div class="w-full max-w-4xl">
  <form>
    <Field.Set>
      <Field.Legend>프로필</Field.Legend>
      <Field.Description>프로필 정보를 입력하세요.</Field.Description>
      <Field.Separator />
      <Field.Group>
        <Field.Field orientation="responsive">
          <Field.Content>
            <Field.Label for="name">이름</Field.Label>
            <Field.Description>
              신원 확인을 위해 전체 이름을 입력하세요
            </Field.Description>
          </Field.Content>
          <Input id="name" placeholder="홍길동" required />
        </Field.Field>
        <Field.Separator />
        <Field.Field orientation="responsive">
          <Field.Content>
            <Field.Label for="message">메시지</Field.Label>
            <Field.Description>
              여기에 메시지를 작성할 수 있습니다. 짧게 작성하는 것이 좋으며,
              100자 이내로 작성하세요.
            </Field.Description>
          </Field.Content>
          <Textarea
            id="message"
            placeholder="안녕하세요!"
            required
            class="min-h-[100px] resize-none sm:min-w-[300px]"
          />
        </Field.Field>
        <Field.Separator />
        <Field.Field orientation="responsive">
          <Button type="submit">제출</Button>
          <Button type="button" variant="outline">취소</Button>
        </Field.Field>
      </Field.Group>
    </Field.Set>
  </form>
</div>

유효성 검사 및 오류

  • 전체 블록을 오류 상태로 전환하려면 Fielddata-invalid를 추가하세요.
  • 보조 기술을 위해 입력 자체에 aria-invalid를 추가하세요.
  • 오류 메시지를 필드와 정렬 상태로 유지하려면 컨트롤 바로 다음 또는 FieldContent 내부에 FieldError를 렌더링하세요.
<Field.Field data-invalid>
  <Field.Label for="email">이메일</Field.Label>
  <Input id="email" type="email" aria-invalid />
  <Field.Error>유효한 이메일 주소를 입력하세요.</Field.Error>
</Field.Field>

접근성

  • Field.SetField.Legend는 키보드 및 보조 기술 사용자를 위해 관련 컨트롤을 그룹화합니다.
  • Fieldrole="group"을 출력하므로 중첩된 컨트롤이 결합될 때 Field.LabelField.Legend에서 라벨링을 상속합니다.
  • 스크린 리더가 명확한 섹션 경계를 만나도록 Field.Separator를 절제하여 적용하세요.