바로 코드로 들어간다.
- 샘플 데이터 양식은 추후 수정 예정
코드
// App.jsx
import React from "react";
import { Dropdown } from "components/buttons";
const smapleData = { data: ["1번", "2번", "3번", "4번"] };
export default function Main() {
return (
<div>
<Dropdown props={smapleData} />
</div>
);
}
// src/components/buttons/index.jsx
export * from "./Dropdown";
// src/components/buttons/Dropdown.jsx
import React, { useState } from "react";
import styled from "styled-components";
const SelectBox = styled.div`
position: relative;
width: 165px;
height: 40px;
padding: 10px;
border-radius: 5px;
background-color: #ffffff;
align-self: center;
border: 1px solid #cccccc;
cursor: pointer;
&::before {
content: "⌵";
position: absolute;
top: 4px;
right: 8px;
color: #777777;
font-size: 20px;
font-weight: bold;
}
`;
const Label = styled.label`
font-size: 14px;
display: inline-block;
`;
const SelectOptions = styled.ul`
position: absolute;
top: 38px;
left: 0;
width: 100%;
max-height: 200px;
overflow-y: auto;
/* border: 1px solid #cccccc; */
// show가 아닌 상태에서 테두리를 없앤다
border: ${(props) => (props.show ? "1px solid #cccccc;" : "none")};
border-radius: 5px;
max-height: ${(props) => (props.show ? "none" : "0")};
background-color: #fefefe;
`;
const Option = styled.li`
font-size: 14px;
padding: 10px;
transition: background-color 0.2s ease-in;
&:hover {
color: white;
border-radius: 5px;
// hover 색상 후보
background: linear-gradient(135deg, #5658df 0%, #2f6dd0 100%);
/* background-color: #dadada; */
/* background-color: #1e90ff; */
}
`;
export const Dropdown = (props) => {
console.log(props.props.data);
const list = props.props.data;
const [currentValue, setCurrentValue] = useState(list[0]);
const [showOptions, setShowOptions] = useState(false);
const handleOnChangeSelectValue = (e) => {
setCurrentValue(e.target.getAttribute("value"));
};
return (
<SelectBox onClick={() => setShowOptions((prev) => !prev)}>
<Label>{currentValue}</Label>
<SelectOptions show={showOptions}>
{list.map((data, index) => (
<Option key={index} value={data} onClick={handleOnChangeSelectValue}>
{data}
</Option>
))}
</SelectOptions>
</SelectBox>
);
};
현재까지 코드의 결과 화면이다.
기능 추가하기
- Dropdwon 박스 바깥쪽을 클릭시 옵션이 사라지는 기능 추가
- 스크롤바 CSS 편집
::-webkit-scrollbar : 스크롤바 전체
::-webkit-scrollbar-thumb : 스크롤 막대
::-webkit-scrollbar-track : 스크롤 막대 외부
적용
import React, { useState, useEffect, useRef } from "react";
import styled from "styled-components";
const SelectBox = styled.div`
position: relative;
width: 165px;
height: 40px;
padding: 10px;
border-radius: 5px;
background-color: #ffffff;
align-self: center;
border: 1px solid #cccccc;
cursor: pointer;
&::before {
content: "⌵";
position: absolute;
top: 4px;
right: 8px;
color: #777777;
font-size: 20px;
font-weight: bold;
}
`;
const Label = styled.label`
font-size: 14px;
display: inline-block;
`;
const SelectOptions = styled.ul`
position: absolute;
top: 38px;
left: 0;
width: 100%;
max-height: 200px;
overflow-y: auto;
height: 200px;
/* border: 1px solid #cccccc; */
// show가 아닌 상태에서 테두리를 없앤다
border: ${(props) => (props.show ? "1px solid #cccccc;" : "none")};
border-radius: 5px;
max-height: ${(props) => (props.show ? "none" : "0")};
background-color: #fefefe;
// 스크롤바 CSS
::-webkit-scrollbar {
width: 4px;
}
::-webkit-scrollbar-thumb {
background-color: #777777;
border-radius: 10px;
}
::-webkit-scrollbar-track {
background-color: #cccccc;
border-radius: 0px 3px 3px 0px;
}
`;
const Option = styled.li`
font-size: 14px;
padding: 10px;
transition: background-color 0.2s ease-in;
&:hover {
color: white;
border-radius: 5px;
// hover 색상 후보
background: linear-gradient(135deg, #5658df 0%, #2f6dd0 100%);
/* background-color: #dadada; */
/* background-color: #1e90ff; */
}
`;
export const Dropdown = (props) => {
// console.log(props.props.data);
const list = props.props.data;
const selectRef = useRef(null);
const [currentValue, setCurrentValue] = useState(list[0]);
const [showOptions, setShowOptions] = useState(false);
const handleOnChangeSelectValue = (e) => {
setCurrentValue(e.target.getAttribute("value"));
};
useEffect(() => {
// NOTE Dropdwon 박스 바깥쪽을 클릭시 옵션이 사라지는 기능
function handleClickOutside(event) {
if (selectRef.current && !selectRef.current.contains(event.target)) {
// dom 바깥 클릭
setShowOptions(false);
}
}
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [selectRef]);
return (
<SelectBox onClick={() => setShowOptions((prev) => !prev)} ref={selectRef}>
<Label>{currentValue}</Label>
<SelectOptions show={showOptions}>
{list.map((data, index) => (
<Option key={index} value={data} onClick={handleOnChangeSelectValue}>
{data}
</Option>
))}
</SelectOptions>
</SelectBox>
);
};
// props Default value
Dropdown.defaultProps = {
name: "초기값",
};
스크롤바가 얇아졌고 바깥쪽을 클릭해도 취소가 된다.
참고 블로그
- 슬라이드바 : https://velog.io/@shyunju7/react16
- 바깥쪽 클릭시 닫힘 : https://codingbroker.tistory.com/66
- 스크롤바 디자인 : https://codingbroker.tistory.com/66
'React' 카테고리의 다른 글
[React] Color Picker 그라데이션 칩 만들기 (No Library) (0) | 2023.06.24 |
---|---|
[React] useLocation을 활용해 사이드(메뉴)바를 현재 주소 기준으로 활성화하기 (0) | 2023.05.21 |
[React] SlideBar - 슬라이드 메뉴 만들기 (0) | 2023.05.11 |
[React] .env 환경변수 설정하기 (0) | 2023.03.06 |
[React] iframe 태그를 활용해 CodePen 코드 가져오기 (0) | 2022.11.02 |