# Component/DropdownInput

> Props: component-dropdowninput.props.txt

## Examples


### Allow Custom Value

options에 없는 값을 허용하기 위해 allowCustomValue을 활성화할 수 있습니다.

```tsx
{
  render: () => {
    const [value, setValue] = useState<string | number | undefined>('직접입력된 값');
    return <Stack direction='column' p={20}>
        <DropdownInput allowCustomValue width={200} value={value} options={[{
        label: '색상',
        value: '색상'
      }, {
        label: '사이즈',
        value: '사이즈'
      }]} placeholder='옵션명을 입력해주세요' onChange={setValue} />
        <BaseText color={semantic_colors.content.secondary}>저장된 값: {value}</BaseText>
      </Stack>;
  },
  parameters: {
    docs: {
      description: {
        story: 'options에 없는 값을 허용하기 위해 allowCustomValue을 활성화할 수 있습니다.'
      }
    }
  }
}
```

### Base

```tsx
{
  args: {
    width: 250,
    placeholder: 'select fruit'
  },
  render: args => {
    const [value, onChange] = useState<number | undefined>();
    return <DropdownInput {...args} options={options} value={value} onChange={v => {
      args.onChange?.(v);
      onChange(v);
    }} />;
  }
}
```

### Controlled

```tsx
{
  render: () => {
    const [value, setValue] = useState<string | number | undefined>(3);
    const handleButtonClick = () => {
      setValue(7);
    };
    return <Stack direction='row'>
        <Stack direction='column' p={6}>
          <DropdownInput width={200} value={value} options={options} placeholder='select fruit' onChange={setValue} />
        </Stack>
        <Stack direction='column' p={6}>
          <Button kind='secondary' onClick={handleButtonClick}>
            set peach
          </Button>
        </Stack>
      </Stack>;
  }
}
```

### Disabled

```tsx
{
  args: {
    width: 250,
    placeholder: 'select fruit'
  },
  render: args => {
    const [value, onChange] = useState<number | undefined>();
    return <DropdownInput {...args} options={options} value={value} onChange={v => {
      args.onChange?.(v);
      onChange(v);
    }} />;
  },
  args: {
    width: 250,
    placeholder: 'select fruit',
    disabled: true
  }
}
```

### Error

```tsx
{
  args: {
    width: 250,
    placeholder: 'select fruit'
  },
  render: args => {
    const [value, onChange] = useState<number | undefined>();
    return <DropdownInput {...args} options={options} value={value} onChange={v => {
      args.onChange?.(v);
      onChange(v);
    }} />;
  },
  args: {
    width: 250,
    status: 'error',
    placeholder: 'select fruit'
  }
}
```

### Flip

```tsx
{
  render: args => {
    const [value, onChange] = useState<number | undefined>();
    return <div>
        <div style={{
        height: '600px'
      }} />
        <Stack direction='row' align='center'>
          <DropdownInput {...args} width={250} options={options} value={value} onChange={v => {
          args.onChange?.(v);
          onChange(v);
        }} />
        </Stack>
      </div>;
  },
  args: {
    placeholder: '옵션 선택하기',
    options: options
  }
}
```

### Search

사용자가 입력한 값과 일치하는 결과가 Dropdown에 표시됩니다.

```tsx
{
  render: () => {
    const [value, setValue] = useState<string | number | undefined>('색상');
    return <Stack direction='column'>
        <DropdownInput width={250} value={value} onChange={setValue} optionFilter={(inputValue, {
        label
      }) => label.includes(inputValue)} placeholder='색상 검색' options={[{
        label: '골드',
        value: 'Gold'
      }, {
        label: '화이트 골드',
        value: 'White Gold'
      }, {
        label: '로즈 골드',
        value: 'Rose Gold'
      }, {
        label: '실버',
        value: 'Silver'
      }]} startElement={<IconSearch color={semantic_colors.content.tertiary} />} endElement={null} />
      </Stack>;
  },
  parameters: {
    docs: {
      description: {
        story: '사용자가 입력한 값과 일치하는 결과가 Dropdown에 표시됩니다.'
      }
    }
  }
}
```

### Size

```tsx
{
  render: () => <Stack direction='column' gap={16}>
      <DropdownInput width={250} placeholder='옵션 선택하기' options={options} size='large' />
      <DropdownInput width={250} placeholder='옵션 선택하기' options={options} size='medium' />
      <DropdownInput width={250} placeholder='옵션 선택하기' options={options} size='small' />
      <DropdownInput width={250} placeholder='옵션 선택하기' options={options} size='xsmall' />
    </Stack>
}
```

### Submit

사용자가 입력한 값과 일치하는 결과가 Dropdown에 표시됩니다.

```tsx
{
  render: () => {
    const [value, setValue] = useState<string | number | undefined>('색상');
    return <form onSubmit={e => {
      e.preventDefault();
      alert('onSubmit');
    }}>
        <Stack direction='column'>
          <DropdownInput width={250} value={value} onChange={setValue} optionFilter={(inputValue, {
          label
        }) => label.includes(inputValue)} placeholder='색상 검색' options={[{
          label: '골드',
          value: 'Gold'
        }, {
          label: '화이트 골드',
          value: 'White Gold'
        }, {
          label: '로즈 골드',
          value: 'Rose Gold'
        }, {
          label: '실버',
          value: 'Silver'
        }]} startElement={<IconSearch color={semantic_colors.content.tertiary} />} endElement={null} />
          <DropdownInput width={250} value={value} onChange={setValue} onKeyDown={event => {
          if (event.key === 'Enter') {
            event.preventDefault();
            // 여기에 제출 로직을 추가할 수 있습니다.
            console.log('Submitted value:', value);
          }
        }} optionFilter={(inputValue, {
          label
        }) => label.includes(inputValue)} placeholder='색상 검색' options={[{
          label: '골드',
          value: 'Gold'
        }, {
          label: '화이트 골드',
          value: 'White Gold'
        }, {
          label: '로즈 골드',
          value: 'Rose Gold'
        }, {
          label: '실버',
          value: 'Silver'
        }]} startElement={<IconSearch color={semantic_colors.content.tertiary} />} endElement={null} />
        </Stack>
        <Button type='submit' kind='primary'>
          Submit
        </Button>
      </form>;
  },
  parameters: {
    docs: {
      description: {
        story: '사용자가 입력한 값과 일치하는 결과가 Dropdown에 표시됩니다.'
      }
    }
  }
}
```

### Test Composition

한글 입력시 Composition 세션에서 키보드 다운 이벤트가 발생되어 마지막에 입력한 글자가 2벌로 입력되는 경우가 있어 이를 방지하고 있습니다.

```tsx
{
  render: () => {
    const [value, setValue] = useState<string | number | undefined>('색상');
    return <Stack direction='column' p={20}>
        <DropdownInput width={200} value={value} options={[{
        label: '색상1',
        value: '색상1'
      }, {
        label: '색상2',
        value: '색상2'
      }, {
        label: '사이즈',
        value: '사이즈'
      }]} placeholder='옵션명을 입력해주세요' onChange={setValue} />
      </Stack>;
  },
  parameters: {
    docs: {
      description: {
        story: '한글 입력시 Composition 세션에서 키보드 다운 이벤트가 발생되어 마지막에 입력한 글자가 2벌로 입력되는 경우가 있어 이를 방지하고 있습니다.'
      }
    }
  }
}
```

### Too Many Options

```tsx
{
  args: {
    width: 250,
    placeholder: 'select option'
  },
  render: args => {
    const [value, onChange] = useState<number | undefined>();
    const options = useMemo(() => {
      return Array.from({
        length: 100_000
      }).map((_, index) => ({
        label: `option ${index}`,
        value: index
      }));
    }, []);
    return <DropdownInput {...args} options={options} value={value} enableVirtualScroll onChange={v => {
      args.onChange?.(v);
      onChange(v);
    }} />;
  }
}
```

### With Form Helper Text

```tsx
{
  render: () => <Stack direction='column'>
      <DropdownInput width={250} placeholder='옵션 선택하기' options={options} status='error' />
      <FormHelperText status='error'>Error Message</FormHelperText>
    </Stack>
}
```

### With Option Filter

```tsx
{
  render: args => {
    const [value, onChange] = useState<number | undefined>();
    return <DropdownInput {...args} options={options} value={value} optionFilter={(inputValue, {
      label
    }) => label.includes(inputValue)} onChange={v => {
      args.onChange?.(v);
      onChange(v);
    }} />;
  }
}
```