Input Dropdown

Input Dropdown คือ View ที่ใช้ในการรับค่าจากรายการที่กำหนดไว้

Source code

Reactjs Styled Component
Copy
import { useEffect, useState } from "react";
import styled, { css } from "styled-components";

import useOutsideClick from "../../util/useOutsideClick";
import IconChevron from "../element/icon/IconChevron";

export default function InputDropdown({
  onChange,
  value, //"all"
  dataList, //[{text:'All',value:'all'}] or //['all','none'] 
  design = "outline",
  width,
  maxHeight = 200,
  className,
  backgroundColor,
  borderRadius = "8px",
  borderColor,
  borderErrorColor = "var(--danger)",
  importantColor = "var(--danger)",
  backgroundDisabledColor = "#f5f5f5",
  style,
  isError,
  disabled,
  placeHolder = "select",
  dropDownGap = 5,
  label,
  fontSize = "16px",
  textTransform = "capitalize",
  important,
}) {
  const outerRef = useOutsideClick(() => setIsFocus(false));

  const [isFocus, setIsFocus] = useState(false);

  const [selectValue, setSelectValue] = useState(placeHolder);

  const [listPosition, setListPosition] = useState();

  useEffect(() => {
    if (value) {
      const findInit = dataList?.find((x) => x.value === value) || value;
      setSelectValue(findInit?.text || findInit);
    }
  }, [value]);

  const handleOnChange = (item) => {
    setIsFocus(false);
    setSelectValue(item.text || item || "");
    if (onChange) {
      onChange(item.value || item || "");
    }
  };

  const handleClickDropdown = (e) => {
    setIsFocus((prev) => !prev);

    const globalMousePos = { y: e.clientY || 0, x: e.clientX || 0 };
    const windowSize = {
      height: e.view.innerHeight || 0,
      width: e.view.innerWidth || 0,
    };

    if (globalMousePos.y + maxHeight < windowSize.height) {
      setListPosition({
        ...listPosition,
        top: outerRef.current.clientHeight + dropDownGap,
        bottom: null,
      });
    } else {
      setListPosition({
        ...listPosition,
        bottom: outerRef.current.clientHeight + dropDownGap,
        top: null,
      });
    }
  };

  return (
    <Styled
      className={className}
      style={style}
      $backgroundColor={backgroundColor}
      $isFocus={isFocus}
      $borderRadius={borderRadius}
      $disabled={disabled}
      $borderColor={borderColor}
      $borderErrorColor={borderErrorColor}
      $backgroundDisabledColor={backgroundDisabledColor}
      $design={design}
      $width={width}
      $maxHeight={maxHeight}
      $listPosition={listPosition}
      $fontSize={fontSize}
      $textTransform={textTransform}
      $importantColor={importantColor}
    >
      {label && <small>{label}</small>}
      {important && <div className="is-important">*</div>}
      <div
        ref={outerRef}
        className={
          "dropdown-inner " +
          (isError ? " input-error" : "") +
          (disabled ? " input-disabled" : "")
        }
      >
        <div className="selected-wrp" onClick={handleClickDropdown}>
          <span
            className={
              "select-text" + (selectValue == placeHolder ? " place-item" : "")
            }
          >
            {selectValue}
          </span>
          <i className="icon-dropdown">
            <IconChevron degree="270" width="7" />
          </i>
        </div>
        {!disabled && isFocus && dataList && (
          <ul className="list">
            {dataList.map((item, index) => (
              <li
                className="item-li"
                key={"item-" + index}
                onClick={() => handleOnChange(item)}
              >
                {item?.text || item || ""}
              </li>
            ))}
          </ul>
        )}
      </div>
    </Styled>
  );
}

const Styled = styled.div`
  position: relative;
  display: inline-flex;
  .is-important {
    color: ${({ $importantColor }) => $importantColor};
    position: absolute;
    top: -14px;
    right: -10px;
  }
  small {
    margin-bottom: 5px;
    font-weight: bold;
    display: block;
  }
  .place-item {
    color: var(--txt-normal-soft);
  }
  .dropdown-inner {
    ${({ $design }) => designStyles($design)}
    border-radius: ${({ $borderRadius }) => $borderRadius};
    position: relative;
    display: inline-flex;
    flex-direction: column;
    user-select: none;
    cursor: pointer;
    width: ${({ $width }) => $width};
    min-width: 200px;
    color: var(--txt-normal);
    font-size: ${({ $fontSize }) => $fontSize};
    .list {
      position: absolute;
      margin: 0;
      min-width: 200px;
      width: ${({ $width }) => $width};
      max-height: ${({ $maxHeight }) => $maxHeight + "px"};
      z-index: 999;
      list-style: none;
      border-radius: ${({ $borderRadius }) => $borderRadius};
      padding: 0;
      top: ${({ $listPosition }) =>
        $listPosition?.top ? $listPosition.top + "px" : null};
      bottom: ${({ $listPosition }) =>
        $listPosition?.bottom ? $listPosition.bottom + "px" : null};
      left: 0;
      overflow-y: auto;
    }
    .list li {
      padding: 10px 12px;
      text-transform: ${({ $textTransform }) => $textTransform};
      display: flex;
    }

    .selected-wrp {
      position: relative;
      width: 100%;
      padding: 12px;
    }
    .select-text {
      margin-right: 10px;
      display: block;
      text-overflow: ellipsis;
      white-space: nowrap;
      overflow: hidden;
      text-transform: ${({ $textTransform }) => $textTransform};
    }
    .icon-dropdown {
      position: absolute;
      right: 12px;
      top: 10px;
      svg path {
        stroke: var(--txt-normal-soft);
      }
    }
    &.input-error {
      border-color: ${({ $borderErrorColor }) => $borderErrorColor};
    }
    &.input-error .list {
      border-color: ${({ $borderErrorColor }) => $borderErrorColor};
    }
    &.input-disabled {
      background-color: ${({ $backgroundDisabledColor }) =>
        $backgroundDisabledColor};
    }
  }
`;

const designStyles = (design) =>
  ({
    solid: css`
      background-color: ${({ $backgroundColor }) => $backgroundColor};
      .list {
        background-color: ${({ $backgroundColor }) => $backgroundColor};
      }
    `,
    outline: css`
      border: 1px solid ${({ $borderColor }) => $borderColor};
      background-color: ${({ $backgroundColor }) => $backgroundColor};
      .list {
        border: 1px solid ${({ $borderColor }) => $borderColor};
        background-color: ${({ $backgroundColor }) => $backgroundColor};
      }
    `,
  }[design]);

Usage

Reactjs Styled Component
Copy
import { useState } from "react";
import InputDropdown from "../../example/InputDropdown";

export default function TestView() {
  const [dropdownValue, setDropdownValue] = useState("A");
  return (
    <div>
      <InputDropdown
        value={dropdownValue}
        dataList={["A", "B"]}
        onChange={(e) => setDropdownValue(e)}
      />
    </div>
  );
}

Properties

Property

Description

Type

Default

value

ค่าปัจจุบันของ dropdown

string

dataList

ชุดข้อมูล

array

design

รูปแบบดีไซน์ พื้นฐานของ view เช่น solid (มีสีพื้นหลัง), outline (มีเส้นขอบ) และ none (ไม่มีสีพื้นหลังและเส้นขอบ)

string

"outline"

width

ความกว้างภายในเนื้อหาของ view

string

maxHeight

ส่วนสูงมากที่สุดของ dropdown box

number

200

className

ใช้กำหนดลักษณะเฉพาะของ view

string

backgroundColor

สีพื้นหลังของ view

string

"var(--background)"

borderRadius

ความโค้งมนของ view

string

"8px"

borderColor

สีของเส้นขอบนอกสุดของ view

string

"var(--border)"

borderErrorColor

สีของเส้นขอบนอกสุดของ view เมื่อ error

string

"var(--danger)"

importantColor

สีดอกจันทร์แสดงความสำคัญ

string

"var(--danger)"

backgroundDisabledColor

สีพื้นหลังของ view เมื่อทำการ diable

string

"#f5f5f5"

style

inline style ของ view

CSSProperties

isError

กำหนดค่า true เมื่อต้องการแสดงกรอบสีแดง

boolean

disabled

เมื่อกำหนดค่า เป็น true จะไม่สามารถทำงานฟังก์ชัน 

boolean

placeHolder

ข้อความตัวอย่าง

string

"select"

dropDownGap

ระยะห่างระหว่าง select กับ dropdown

number

5

label

คำอธิบายของ view

string

fontSize

ขนาดตัวอักษรของ view

string

"16px"

textTransform

กำหนด design ของ text ใน view

string

"capitalize"

important

กำหนดค่าเป็น true จะแสดงสัญลักษณ์ดอกจันทร์บน view

boolean

onChange

ฟังก์ชันจะทำงานเมื่อทำการเปลี่ยนค่า

function

Requirements

styled-component react

ยักซ่า (Yakxar)
สร้างสรรค์และแบ่งปันสื่อดิจิทัลง่ายๆ ที่นี่
© 2025 ยักซ่า (Yakxar)