🌐 Web/React

[React + TypeScript] select 직접 구현하기(1)

dlalwl_jpg 2024. 1. 22. 02:25

💬

select tag를 커스텀하여 디자인을 변경하는 방법도 있지만 디자인 요소가 많이 수정되어야 할 것 같아 직접 구현해볼 것이다. 처음에는 react-select라이브러리를 사용하려고 했으나 라이브러리를 커스텀하고 기능들을 변경하는데 시행착오가 있었다. 그래서 직접 구현을 해볼 것이다.

나는 typeScript와 styled-component를 이용하여 구현하였다.

styled-component와 관련된 코드는 SignUpForm.styled.ts에 작성하였고, css를 제외한 나머지는 GroupType.tsx에 작성하였다.

전체 코드는 밑에 이어지는 글에 있다.

https://studybook.tistory.com/106

 

[React + TypeScript] select 직접 구현하기(2)

https://studybook.tistory.com/104 [React + TypeScript] select 직접 구현하기(1) select tag를 커스텀하여 디자인을 변경하는 방법도 있지만 디자인 요소가 많이 수정되어야 할 것 같아 직접 구현해볼 것이다. 처음

studybook.tistory.com


1. select 기본틀 구현 및 화살표 커스텀하기

아래 사진처럼 기본틀을 만들고 화살표를 커스텀할 것이다.


GroupType.tsx

import * as S from './SignUpForm.style';

function GroupType(){

    return(
        <div>
            <S.groupTypeBox>
                <S.groupTypeLabel>동아리</S.groupTypeLabel>
            </S.groupTypeBox>
        </div>
    );
}

export default GroupType;

<S.groupTypeBox>는, <S.groupTyleLabel>은 <div>과 같다. 

즉, 각각 <div>태그로 바꿔도 된다는 것이다.


SignUpForm.style.ts

import styled from 'styled-components'
 
//그룹 분류 select 박스
export const groupTypeBox = styled.div`
    position: relative;
    width: 399px;
    height: 60px;
    border-radius: 11px;
    border: 2px solid var(--gray-01, #303030);
    padding: 21px 22px;

    //화살표 커스텀
    background:url('/images/groupTypePolygon.svg') no-repeat right 23px center; //화살표 사진 가져오기
    background-size: 14px; //화살표 크기
`;

//그룹 분류 라벨
export const groupTypeLabel = styled.div`
    display: flex;
    border: 0 none;
    background: transparent;
    cursor: pointer;
    font-size: 15px;
    font-weight: 600;
`;

화살표를 커스텀하기 위해서는 background를 이용해 화살표의 이미지 주소를 가져와야 한다.

위 코드에서 images폴더는 public폴더 안에 있다.

right 23px center는 오른쪽으로부터 23px떨어지도록, 위아래로 가운데에 화살표를 위치시킨다. 


2. select 열린 박스 구현 및 커스텀하기

select박스를 클릭하면 아래 나오는 option을 구현할 것이다.

그리고 option에 마우스를 갖다대면 색이 변하도록 커스텀 할 것이다.


GroupType.tsx

import * as S from './SignUpForm.style';

function GroupType(){

    return(
        <div>
            <S.groupTypeBox>
                <S.groupTypeLabel>동아리</S.groupTypeLabel>
                <S.groupTypeUl>
                    <S.groupTypeLiTop>동아리</S.groupTypeLiTop>
                    <S.groupTypeLi>학생회</S.groupTypeLi>
                    <S.groupTypeLi>학술 모임</S.groupTypeLi>
                    <S.groupTypeLiBottom>기타</S.groupTypeLiBottom>
                </S.groupTypeUl>
            </S.groupTypeBox>
        </div>
    );
}

export default GroupType;

(위에서 이어서 작성한 코드이다.)

<S.groupTypeUl>은 <ul>, <S.groupTypeLiTop>,  <S.groupTypeLi>, <S.groupTypeLiBottom>은 <li> 태그와 같다. 

<S.groupTypeUl>이 option박스 역할을 하고,  <S.groupTypeLiTop>,  <S.groupTypeLi>, <S.groupTypeLiBottom>가 option과 같은 역할을 한다.

(동아리와 기타만 다른 태그를 이용한 이유는 커스텀할 때 설명할 것이다.)


SignUpForm.style.ts

 
//그룹 분류 선택리스트 박스(option박스)
export const groupTypeUl = styled.ul`
    width: 399px;
    height: 236px;
    border-radius: 11px;
    border: 2px solid #FF4A4A;
    position: absolute;
    background: #fff;
    margin: 28px 0 0 -24px; //label기준으로 위치 조정
    cursor: pointer;
`;

//그룹 분류 option
export const groupTypeLi = styled.li`
    font-size: 15px;
    font-weight: 600;
    height: 58px;
    padding: 19px 25px;

    //마우스 닿으면 색 변경
    &:hover{
        background: #FFF2F2;
    }
`;

//그룹 분류 option(동아리)
export const groupTypeLiTop = styled(groupTypeLi)`
    border-radius: 9px 9px 0px 0px;
`;

//그룹 분류 option(기타)
export const groupTypeLiBottom = styled(groupTypeLi)`
    border-radius: 0px 0px 9px 9px;
`;

groupTypeUl에서 backgroud를 설정하지 않으면 투명해진다.

export const groupTypeLiTop = styled(groupTypeLi)는 groupTypeLi의 css를 groupTypeLiTop에도 똑같이 적용하면서 다른 부분만 변경하는 것이다. 즉, css의 재사용이다.

hover를 이용해서 마우스가 닿는 부분의 색을 변경하도록 한다.

동아리와 기타 option만 따로 만든 이유는 모서리를 필요한 부분을 둥글게 디자인 해주어야 색이 변경될 때 바깥으로 나오지 않게 된다.

아래 사진에서 왼쪽이 모서리를 둥글게 적용 안 한 것이고, 오른쪽이 따로 둥글게 디자인 해준 것이다.


3. Option박스 열고 닫는 기능 추가 및 열고 닫을 때 border 색 변경하기

기존에는 select박스의 border 검정색이었지만 마우스를 위에 올리고 클릭하면 border색깔이 바뀌면서 option들이 보이도록 기능을 구현할 것이다.

 

박스가 닫혀 있을 때

 

박스가 열렸을 때


GroupType.tsx

import * as S from './SignUpForm.style';
import { useState } from 'react';

function GroupType(){

    //그룹 분류 option열기
    const [isOption, setIsOption] = useState(false);
    const onClickLabel = () => {
        setIsOption(!isOption);
    };

    return(
        <div>
            <S.groupTypeBox toggle={isOption}>
                <S.groupTypeLabel onClick={onClickLabel}>동아리</S.groupTypeLabel>
                <S.groupTypeUl toggle={isOption}>
                    <S.groupTypeLiTop>동아리</S.groupTypeLiTop>
                    <S.groupTypeLi>학생회</S.groupTypeLi>
                    <S.groupTypeLi>학술 모임</S.groupTypeLi>
                    <S.groupTypeLiBottom>기타</S.groupTypeLiBottom>
                </S.groupTypeUl>
            </S.groupTypeBox>
        </div>
    );
}

export default GroupType;

<S.groupTypeLabel>을 클릭하면 onClickLabel함수가 실행된다. 그럼 isOption의 값을 기존의 값에서 반대 값으로 바꿔준다. 즉, isOption이 true였으면 false, false였으면 true로 변경한다.

그리고 변경된 isOption값에 따라 <S.groupTypeBox>의 border색상과 <S.groupTypeUl>의 보이는 상태가 달라지므로 toggle을 이용해 값을 SignUpForm.style.ts에 전달할 것이다.


SignUpForm.style.ts

//그룹 분류 select 박스
export const groupTypeBox = styled.div<{toggle:boolean}>`
    position: relative;
    width: 399px;
    height: 60px;
    border-radius: 11px;
    border: 2px solid ${props=>(props.toggle ? '#FF4A4A': '#303030')};
    padding: 21px 22px;

    //화살표 커스텀
    background:url('/images/groupTypePolygon.svg') no-repeat right 23px center; //화살표 사진 가져오기
    background-size: 14px; //화살표 크기
   
    &:hover{
        border: 2px solid #FF4A4A;
    }
`;
 
//그룹 분류 선택리스트 박스(option박스)
export const groupTypeUl = styled.ul<{toggle:boolean}>`
    width: 399px;
    height: 236px;
    border-radius: 11px;
    border: 2px solid #FF4A4A;
    position: absolute;
    background: #fff;
    margin: 31px 0 0 -24px; //label기준으로 위치 조정
    cursor: pointer;
    display:${props=>(props.toggle ? 'null': 'none')};
`;

변경된 부분만 코드를 다시 가져왔다.

toggle을 이용해 isOption의 값을 전달 받았으면 true일 경우와 false일 경우에 따라 색을 다르게 설정한다.

그리고 option은 false일 때 안 보이고, true일 때는 보이도록 display: none으로 설정하였다.


- 참고한 블로그

https://wazacs.tistory.com/34

 

select 태그 커스텀 하기, 혹은 직접 만들기 (feat. javascript)

1. Select CSS Customizing Select 태그의 외형은 주로 각 브라우저에서 정의 합니다. 보다 시피 크롬(왼쪽), IE(오른쪽) 이 똑같이 보이면서도 미세 하게 다름니다. 공통적으로 둘 다 그리 예쁘게 생기진

wazacs.tistory.com

https://velog.io/@bommy5799/CSS-Styled-Components-TypeScript-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%97%90-props-%EA%B0%92-%EC%A0%84%EB%8B%AC%ED%95%98%EA%B8%B0

 

[🐋 CSS] Styled Components & TypeScript - 컴포넌트에 props 값 전달하기

스타일 컴포넌트 & 타입 스크립트로 프로젝트를 진행하던 도중에해당 스크롤 위치 조건을 달성한 경우에, 컴포넌트를 고정시키고 싶었다. 하지만 일반 리액트로 진행하는 것처럼 props로 단순 조

velog.io

https://velog.io/@harenohee/Typescript-Mouse-value-%EA%B0%92-%EA%B0%80%EC%A0%B8%EC%98%A4%EA%B8%B0

 

[Typescript, React] 태그 클릭 시 value 값 가져오기

개인블로그를 만들어보고 있는데, 벨로그나 티스토리처럼 태깅 작업도 추가하고 싶었다. 버튼 요소인 태그 클릭 -> 해당 value값을 정상적으로 출력하는지를 보려고했는데, 에러메세지; 'EventTarget

velog.io