Design System
  • Home
  • Components
  • Tokens
  • Guidelines
  • Select

    Select는 사용자가 옵션 목록에서 하나의 값을 선택할 수 있는 드롭다운 컴포넌트입니다. Radix UI의 Select 컴포넌트를 기반으로 구현되었습니다.

    • 접근성이 고려된 드롭다운 메뉴를 제공합니다
    • 그룹화된 옵션을 지원합니다
    • 키보드 탐색과 애니메이션 효과가 포함되어 있습니다

    Installation

    npx @jongh/cli add select

    Usage

    Select 컴포넌트는 Radix UI의 Select 컴포넌트를 기반으로 구현되었으며, 여러 하위 컴포넌트로 구성됩니다.

    컴포넌트 구조

    • Select.Root: 셀렉트의 모든 파트를 감싸는 컨테이너입니다.
    • Select.Trigger: 드롭다운을 열고 닫는 버튼입니다.
    • Select.Value: 현재 선택된 값을 표시합니다.
    • Select.Portal: 드롭다운 메뉴를 DOM의 최상위 레벨로 포탈링합니다.
    • Select.Content: 드롭다운 메뉴의 콘텐츠를 담는 컨테이너입니다.
    • Select.Viewport: 드롭다운 메뉴의 뷰포트를 정의합니다.
    • Select.Item: 개별 선택 항목을 나타냅니다.
    • Select.ItemText: 항목의 텍스트 부분을 나타냅니다.
    • Select.ItemIndicator: 선택된 항목을 표시하는 인디케이터입니다.
    • Select.Group: 관련 항목들을 그룹화합니다.
    • Select.Label: 그룹의 레이블을 정의합니다.
    • Select.Separator: 항목 그룹 간의 구분선을 제공합니다.
    • Select.Arrow: 콘텐츠와 트리거를 연결하는 화살표를 나타냅니다.
    • Select.ScrollUpButton: 뷰포트에서 위로 스크롤하는 버튼입니다.
    • Select.ScrollDownButton: 뷰포트에서 아래로 스크롤하는 버튼입니다.

    Props

    Select.Root

    • defaultValue (string): 초기 선택된 값입니다 (비제어 모드).
    • value (string): 현재 선택된 값입니다 (제어 모드).
    • onValueChange ((value: string) => void): 값이 변경될 때 호출되는 함수입니다 (제어 모드).
    • open (boolean): 드롭다운의 열림 상태를 제어합니다 (제어 모드).
    • onOpenChange ((open: boolean) => void): 드롭다운의 열림 상태가 변경될 때 호출되는 함수입니다.
    • disabled (boolean): 셀렉트의 비활성화 여부를 지정합니다.
    • name (string): 셀렉트의 폼 이름을 지정합니다.
    • required (boolean): 셀렉트의 필수 입력 여부를 지정합니다.

    Select.Trigger

    • asChild (boolean): 트리거 요소를 자식 요소로 대체합니다. 기본값은 false입니다.

    Select.Value

    • placeholder (string): 아무것도 선택되지 않았을 때 표시되는 텍스트입니다.
    • asChild (boolean): 값 요소를 자식 요소로 대체합니다. 기본값은 false입니다.

    Select.Portal

    • container (HTMLElement): 포탈링할 컨테이너 요소를 지정합니다.
    • forceMount (boolean): 포탈 컴포넌트를 강제로 마운트합니다.

    Select.Content

    • asChild (boolean): 콘텐츠 요소를 자식 요소로 대체합니다. 기본값은 false입니다.
    • position ("popper" | "item-aligned"): 콘텐츠의 위치 전략을 지정합니다. 기본값은 "popper"입니다.
    • side ("top" | "right" | "bottom" | "left"): 콘텐츠가 표시될 트리거 기준 위치입니다.
    • sideOffset (number): 콘텐츠와 트리거 사이의 거리를 지정합니다.
    • align ("start" | "center" | "end"): 콘텐츠의 정렬 방향을 지정합니다.
    • alignOffset (number): 정렬 오프셋을 지정합니다.
    • avoidCollisions (boolean): 뷰포트와의 충돌을 방지할지 여부를 지정합니다.
    • forceMount (boolean): 콘텐츠 컴포넌트를 강제로 마운트합니다.

    Select.Item

    • value (string): 이 항목의 고유한 값입니다.
    • disabled (boolean): 항목의 비활성화 여부를 지정합니다.
    • textValue (string): 항목의 텍스트 표현을 지정합니다 (검색용).
    • asChild (boolean): 항목 요소를 자식 요소로 대체합니다. 기본값은 false입니다.

    Accessibility

    Select 컴포넌트는 WAI-ARIA Listbox 디자인 패턴을 따르고 있습니다.

    • Select.Trigger에는 자동으로 aria-haspopup="listbox"가 설정됩니다.
    • Select.Content에는 자동으로 role="listbox"가 설정됩니다.
    • Select.Item에는 자동으로 role="option"이 설정됩니다.
    • 셀렉트가 열리면 포커스가 콘텐츠로 이동하고, 닫히면 트리거로 돌아갑니다.
    • 화살표 키를 사용하여 항목 간 탐색이 가능합니다.
    • Home 및 End 키로 처음과 마지막 항목으로 이동할 수 있습니다.
    • 문자 입력으로 항목을 검색할 수 있습니다.
    • 필요한 ARIA 속성이 자동으로 설정됩니다.

    Example

    기본 사용 예시

    import * as Select from "@/components/select"
    
    const SelectExample = () => (
      <Select.Root>
        <Select.Trigger>
          <Select.Value placeholder="옵션을 선택하세요" />
        </Select.Trigger>
        <Select.Content>
          <Select.Viewport>
            <Select.Item value="option1">옵션 1</Select.Item>
            <Select.Item value="option2">옵션 2</Select.Item>
            <Select.Item value="option3">옵션 3</Select.Item>
          </Select.Viewport>
        </Select.Content>
      </Select.Root>
    )

    그룹화된 예시

    import * as Select from "@/components/select"
    
    const GroupedSelectExample = () => (
      <Select.Root>
        <Select.Trigger>
          <Select.Value placeholder="과일을 선택하세요" />
        </Select.Trigger>
        <Select.Content>
          <Select.Viewport>
            <Select.Group>
              <Select.Label>국내산</Select.Label>
              <Select.Item value="apple">사과</Select.Item>
              <Select.Item value="pear"></Select.Item>
            </Select.Group>
            <Select.Separator />
            <Select.Group>
              <Select.Label>수입산</Select.Label>
              <Select.Item value="banana">바나나</Select.Item>
              <Select.Item value="orange">오렌지</Select.Item>
            </Select.Group>
          </Select.Viewport>
        </Select.Content>
      </Select.Root>
    )

    비활성화된 항목 예시

    import * as Select from "@/components/select"
    
    const DisabledItemExample = () => (
      <Select.Root>
        <Select.Trigger>
          <Select.Value placeholder="옵션을 선택하세요" />
        </Select.Trigger>
        <Select.Content>
          <Select.Viewport>
            <Select.Item value="option1">옵션 1</Select.Item>
            <Select.Item value="option2" disabled>
              옵션 2 (비활성화)
            </Select.Item>
            <Select.Item value="option3">옵션 3</Select.Item>
          </Select.Viewport>
        </Select.Content>
      </Select.Root>
    )

    제어 컴포넌트 예시

    import * as Select from "@/components/select"
    import { useState } from "react"
    
    const ControlledSelectExample = () => {
      const [value, setValue] = useState("")
    
      return (
        <div>
          <p>선택된 값: {value || "없음"}</p>
          <Select.Root value={value} onValueChange={setValue}>
            <Select.Trigger>
              <Select.Value placeholder="옵션을 선택하세요" />
            </Select.Trigger>
            <Select.Content>
              <Select.Viewport>
                <Select.Item value="option1">옵션 1</Select.Item>
                <Select.Item value="option2">옵션 2</Select.Item>
                <Select.Item value="option3">옵션 3</Select.Item>
              </Select.Viewport>
            </Select.Content>
          </Select.Root>
        </div>
      )
    }

    더 자세한 내용

    더 자세한 내용은 Radix UI Select 공식 문서를 참조하세요.