Featuring Design System
Legacy

CoreSelectPrim

컴파운드 패턴으로 구성된 Select 컴포넌트입니다. 단일 값에 대한 선택을 지원합니다.

Usage

기본 사용법

import { SelectPrim } from '@featuring-corp/components';

<SelectPrim.Root required width="240px">
  <SelectPrim.Label tooltip="도움말">Label</SelectPrim.Label>
  <SelectPrim.Trigger>
    <SelectPrim.Value placeholder="옵션을 선택하세요" />
  </SelectPrim.Trigger>
  <SelectPrim.HelperText>Helper Text</SelectPrim.HelperText>
  <SelectPrim.Portal>
    <SelectPrim.Content>
      <SelectPrim.Item value="option1">Option 1</SelectPrim.Item>
      <SelectPrim.Item value="option2">Option 2</SelectPrim.Item>
      <SelectPrim.Item value="option3" disabled>Option 3 (disabled)</SelectPrim.Item>
    </SelectPrim.Content>
  </SelectPrim.Portal>
</SelectPrim.Root>

제어된 컴포넌트 (Controlled Component)

import { useState } from 'react';
import { SelectPrim } from '@featuring-corp/components';

const [selected, setSelected] = useState('option1');

<SelectPrim.Root 
  value={selected} 
  onValueChange={setSelected}
  required
  width="240px"
>
  <SelectPrim.Label>Label</SelectPrim.Label>
  <SelectPrim.Trigger>
    <SelectPrim.Value />
  </SelectPrim.Trigger>
  <SelectPrim.Portal>
    <SelectPrim.Content>
      <SelectPrim.Item value="option1">Option 1</SelectPrim.Item>
      <SelectPrim.Item value="option2">Option 2</SelectPrim.Item>
    </SelectPrim.Content>
  </SelectPrim.Portal>
</SelectPrim.Root>

그룹과 구분선 사용

import { SelectPrim } from '@featuring-corp/components';
import { IconAccountFilled, IconTuneFilled } from '@featuring-corp/icons';
import { flex } from '@styles/utils';

<SelectPrim.Root required width="240px">
  <SelectPrim.Label>Label</SelectPrim.Label>
  <SelectPrim.Trigger>
    <SelectPrim.Value />
  </SelectPrim.Trigger>
  <SelectPrim.Portal>
    <SelectPrim.Content>
      <SelectPrim.Group>
        <SelectPrim.GroupLabel>옵션 그룹 1</SelectPrim.GroupLabel>
        <SelectPrim.Item value="option1">
          <div className={flex({ gap: 'spacing-200' })}>
            <IconAccountFilled size="12px" />
            Option 1
          </div>
        </SelectPrim.Item>
        <SelectPrim.Item value="option2">
          <div className={flex({ gap: 'spacing-200' })}>
            <IconTuneFilled size="12px" />
            Option 2
          </div>
        </SelectPrim.Item>
      </SelectPrim.Group>
      <SelectPrim.Separator />
      <SelectPrim.Group>
        <SelectPrim.GroupLabel>옵션 그룹 2</SelectPrim.GroupLabel>
        <SelectPrim.Item value="option3">Option 3</SelectPrim.Item>
        <SelectPrim.Item value="option4">Option 4</SelectPrim.Item>
      </SelectPrim.Group>
      <SelectPrim.Separator />
      <SelectPrim.Item value="option5">Option 5</SelectPrim.Item>
    </SelectPrim.Content>
  </SelectPrim.Portal>
</SelectPrim.Root>

함수형 children을 사용한 커스텀 아이템

import { SelectPrim } from '@featuring-corp/components';
import { CoreRadio } from '@featuring-corp/components';

<SelectPrim.Root required width="240px">
  <SelectPrim.Label>Label</SelectPrim.Label>
  <SelectPrim.Trigger>
    <SelectPrim.Value />
  </SelectPrim.Trigger>
  <SelectPrim.Portal>
    <SelectPrim.Content>
      <SelectPrim.Item value="option1">
        {(selected) => (
          <CoreRadio 
            label="Option 1" 
            checked={selected} 
            onChange={() => {}} 
          />
        )}
      </SelectPrim.Item>
      <SelectPrim.Item value="option2">
        {(selected) => (
          <CoreRadio 
            label="Option 2" 
            checked={selected} 
            onChange={() => {}} 
          />
        )}
      </SelectPrim.Item>
    </SelectPrim.Content>
  </SelectPrim.Portal>
</SelectPrim.Root>

커스텀 Value 표시

import { useState } from 'react';
import { SelectPrim } from '@featuring-corp/components';
import { CoreTag } from '@featuring-corp/components';

const [selected, setSelected] = useState('option1');

const options = {
  option1: { label: 'Option 1', display: <CoreTag text="Option 1" /> },
  option2: { label: 'Option 2', display: <CoreTag text="Option 2" /> },
  option3: { label: 'Option 3', display: <CoreTag text="Option 3" /> },
};

<SelectPrim.Root 
  value={selected} 
  onValueChange={setSelected}
  required
  width="240px"
>
  <SelectPrim.Label tooltip="도움말">Label</SelectPrim.Label>
  <SelectPrim.Trigger>
    <SelectPrim.Value>
      {options[selected]?.display}
    </SelectPrim.Value>
  </SelectPrim.Trigger>
  <SelectPrim.Portal>
    <SelectPrim.Content>
      {Object.entries(options).map(([value, { label }]) => (
        <SelectPrim.Item key={value} value={value}>
          {label}
        </SelectPrim.Item>
      ))}
    </SelectPrim.Content>
  </SelectPrim.Portal>
</SelectPrim.Root>

상태와 크기 설정

import { SelectPrim } from '@featuring-corp/components';

<SelectPrim.Root 
  status="error" 
  size="lg" 
  width="300px"
  required
  disabled={false}
  readonly={false}
>
  <SelectPrim.Label>Label</SelectPrim.Label>
  <SelectPrim.Trigger>
    <SelectPrim.Value />
  </SelectPrim.Trigger>
  <SelectPrim.HelperText status="error">
    에러 메시지가 표시됩니다
  </SelectPrim.HelperText>
  <SelectPrim.Portal>
    <SelectPrim.Content height={200}>
      <SelectPrim.Item value="option1">Option 1</SelectPrim.Item>
      <SelectPrim.Item value="option2">Option 2</SelectPrim.Item>
    </SelectPrim.Content>
  </SelectPrim.Portal>
</SelectPrim.Root>

Props

SelectPrim.Root

가장 상위 컴포넌트로, Select 전체를 감싸는 역할을 합니다.
해당 컴포넌트를 통해 내부적으로 많은 기능을 컨트롤하기 때문에, 반드시 포함되어야하는 컴포넌트입니다.
Root 컴포넌트에 주입된 status, size, width, readonly, required, disabled props는 하위 컴포넌트에 모두 전달됩니다.

Prop

Type

SelectPrim.Label

Select의 라벨을 표시합니다.

Prop

Type

SelectPrim.Trigger

Select의 선택된 값을 표시합니다. button element로 되어 있습니다.

Prop

Type

SelectPrim.Value

선택된 값을 표시합니다. Trigger 내부에서 사용합니다.

Prop

Type

SelectPrim.HelperText

Select의 헬퍼 텍스트를 표시합니다.

Prop

Type

SelectPrim.Portal

Select의 옵션 목록을 렌더링할 포탈입니다.

Select.SelectPortalProps 타입을 확장한 컴포넌트입니다.

SelectPrim.Content

Select의 옵션 목록을 표시합니다.

Prop

Type

SelectPrim.Item

옵션 목록 내부의 아이템입니다.
children에 작성한 내용이 선택 시에도 자동으로 적용됩니다.

Prop

Type

SelectPrim.Group

옵션 목록 내부의 그룹입니다.

Select.SelectGroupProps 타입을 확장한 컴포넌트입니다.

SelectPrim.GroupLabel

옵션 목록 내부의 그룹 라벨입니다.

Select.SelectLabelProps 타입을 확장한 컴포넌트입니다.

SelectPrim.Separator

옵션 목록 내부의 구분선입니다.

Select.SelectSeparatorProps 타입을 확장한 컴포넌트입니다.

SelectStatus

Prop

Type

SelectSize

Prop

Type

CoreTooltipProps

CoreTooltip 컴포넌트의 props를 참조하세요.

스타일

기본 스타일 속성

Label:

  • display: flex
  • justify-content: flex-start
  • align-items: center
  • margin-bottom: spacing-150 (6px)
  • typography: heading[1]
  • color: text-2 (기본), text-4 (disabled)

Label Required:

  • margin-left: spacing-50 (2px)

Label Icon:

  • margin-left: spacing-100 (4px)

Select Trigger:

  • display: flex
  • justify-content: space-between
  • gap: spacing-200 (8px)
  • padding-x: spacing-250 (10px)
  • border-radius: radius-100
  • border: 1px solid border[1]
  • background-color: background-1 (기본), background-2 (hover)
  • color: text-1 (기본), text-5 (placeholder)
  • cursor: pointer
  • width: auto (기본값)

Select Value:

  • display: block
  • flex-grow: 1

Select Value Placeholder:

  • display: -webkit-box
  • -webkit-box-orient: vertical
  • word-wrap: break-word
  • text-overflow: ellipsis
  • overflow: hidden
  • white-space: pre-wrap
  • word-break: break-all
  • -webkit-line-clamp: 1

Content Container:

  • background-color: background-1
  • padding: spacing-200 (8px)
  • border-radius: radius-100
  • elevation: elevation-8
  • width: auto (기본값)
  • height: auto (기본값)
  • overflow: auto

Select Item:

  • display: flex
  • gap: spacing-150 (6px)
  • border-radius: radius-100
  • min-height: 28px
  • cursor: pointer (disabled: off), not-allowed (disabled: on)

Helper Text:

  • display: flex
  • gap: spacing-100 (4px)
  • margin-top: spacing-100 (4px)
  • typography: body[1]

Group Label:

  • padding-x: spacing-200 (8px)
  • padding-y: spacing-100 (4px)
  • color: text-3
  • typography: body[1]

Separator:

  • margin-y: spacing-300 (12px)
  • margin-x: spacing-200 (8px)
  • border-top: 1px solid border-default

Size Variants (Trigger)

  • sm: typography: body[1], min-height: 28px, height: max-content
  • md: typography: body[2], min-height: 32px, height: max-content
  • lg: typography: body[2], min-height: 40px, height: max-content

Size Variants (Item)

  • sm: typography: body[1], padding-y: spacing-50 (2px)
  • md: typography: body[2], padding-y: spacing-100 (4px)
  • lg: typography: body[2], padding-y: spacing-200 (8px)

Status Variants (Trigger)

  • none: border-color: border[1]
  • warning: border-color: support-warning[3]
  • error: border-color: support-error[3]

Helper Text Status Variants

  • none: color: text-3
  • warning: color: support-warning-3
  • error: color: support-error-3

Select Item States

  • Disabled (on): background-color: toggle-disabled-bg, color: toggle-disabled-text, cursor: not-allowed
  • Disabled (off): data-highlighted: background-color: primary[10], color: primary[100], cursor: pointer

States (상태별 토큰)

Select Trigger:

  • Default: background-color: background-1, border: 1px solid border[1], color: text-1
  • Hover: background-color: background-2, border-color: border-2
  • Focus (not readonly, not disabled): border-color: primary[50]
  • Data-state="open": border-color: primary[50]
  • Readonly: border-color: border[2], background-color: background[4], color: text[1], cursor: auto
  • Disabled: border-color: border[2], background-color: background[4], color: text[4], cursor: not-allowed
  • Placeholder: color: text[5]