Html에 있는 select태그, option태그로는 커스텀에 한계가 있어 직접 만들어보는 방법을 알아보았다.
Html
기본 구조는 select태그 역할을 하는 선택된 값과 option들 값들을 분리하여 클래스 명이 selectBox인 div 태그 안에 배치 한다.
<section> <!-- 1번째 select --> <div class="selectBox"> <div class="selected"> <div class="selected-value">drink</div> <div class="arrow"> <img src="/public/image/downArrow.svg" alt="arrow" /> </div> </div> <ul class="optionList"> <li class="option">coffee</li> <li class="option">water</li> <li class="option">latte</li> <li class="option">jucie</li> </ul> </div> <!-- 2번째 select --> <div class="selectBox"> <div class="selected"> <div class="selected-value">food</div> <div class="arrow"> <img src="/public/image/downArrow.svg" alt="arrow" /> </div> </div> <ul class="optionList"> <li class="option">pizza</li> <li class="option">rice</li> <li class="option">burger</li> <li class="option">bread</li> </ul> </div> </section>
Css
원하는 모양으로 커스텀을 한다.
section { display: flex; align-items: center; justify-content: center; font-size: 14px; margin-top: 20px; } .selectBox { cursor: pointer; margin-right: 20px; } .selected { width: 150px; display: flex; align-items: center; justify-content: space-between; padding: 8px 5px; border-radius: 4px; border: 2px solid rgb(0, 180, 45); } .select .selected .selected-value { max-width: 90px; } .arrow { display: flex; align-items: center; justify-content: center; width: 10px; height: 10px; } .arrow img { width: 100%; } .selectBox .optionList { position: absolute; margin-top: 4px; width: 150px; border-radius: 4px; background: #fff; cursor: pointer; max-height: 0; overflow: hidden; transition: 0.5s ease-in; } .selectBox .option { border-left: 2px solid rgb(0, 180, 45); border-right: 2px solid rgb(0, 180, 45); } .selectBox .option:first-of-type { border-top: 2px solid rgb(0, 180, 45); } .selectBox .option:last-of-type { border-bottom: 2px solid rgb(0, 180, 45); } .selectBox.active .optionList { max-height: 500px; } .selectBox.active .arrow { transform: scaleY(-1); } .option { padding: 8px 5px; } .option:hover { background: rgb(180, 211, 188); }
Javascript
Javascript을 통해 select 기능을 만들었다.
<script> // 모든 셀렉션 박스 엘리먼트 선택 const selectBoxElements = document.querySelectorAll(".selectBox"); //.optionList function toggleSelectBox(selectBox) { selectBox.classList.toggle("active"); } // 옵션 선택 함수 / closest() - 가장 가까운 조상 function selectOption(optionElement) { const selectBox = optionElement.closest(".selectBox"); const selectedElement = selectBox.querySelector(".selected-value"); selectedElement.textContent = optionElement.textContent; } // 각 셀렉션 박스에 클릭 이벤트 리스너 추가 selectBoxElements.forEach((selectBoxElement) => { selectBoxElement.addEventListener("click", function (e) { const targetElement = e.target; const isOptionElement = targetElement.classList.contains("option"); if (isOptionElement) { selectOption(targetElement); } toggleSelectBox(selectBoxElement); }); }); // 문서 전체에 클릭 이벤트 리스너 추가 // 모든 셀렉션 박스 이외의 부분을 클릭했을 때, // 모든 셀렉션 박스에서 'active' 클래스를 제거하여 옵션 목록을 숨긴다. document.addEventListener("click", function (e) { const targetElement = e.target; const isSelect = targetElement.classList.contains("selectBox") || targetElement.closest(".selectBox"); if (isSelect) { return; } // 모든 셀렉션 박스에서 'active' 클래스 제거 const allSelectBoxElements = document.querySelectorAll(".selectBox"); allSelectBoxElements.forEach((boxElement) => { boxElement.classList.remove("active"); }); }); </script>
전체코드
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> section { display: flex; align-items: center; justify-content: center; font-size: 14px; margin-top: 20px; } .selectBox { cursor: pointer; margin-right: 20px; } .selected { width: 150px; display: flex; align-items: center; justify-content: space-between; padding: 8px 5px; border-radius: 4px; border: 2px solid rgb(0, 180, 45); } .select .selected .selected-value { max-width: 90px; } .arrow { display: flex; align-items: center; justify-content: center; width: 10px; height: 10px; } .arrow img { width: 100%; } .selectBox .optionList { position: absolute; margin-top: 4px; width: 150px; border-radius: 4px; background: #fff; cursor: pointer; max-height: 0; overflow: hidden; transition: 0.5s ease-in; } .selectBox .option { border-left: 2px solid rgb(0, 180, 45); border-right: 2px solid rgb(0, 180, 45); } .selectBox .option:first-of-type { border-top: 2px solid rgb(0, 180, 45); } .selectBox .option:last-of-type { border-bottom: 2px solid rgb(0, 180, 45); } .selectBox.active .optionList { max-height: 500px; } .selectBox.active .arrow { transform: scaleY(-1); } .option { padding: 8px 5px; } .option:hover { background: rgb(180, 211, 188); } </style> </head> <body> <section> <div class="selectBox"> <div class="selected"> <div class="selected-value">drink</div> <div class="arrow"> <img src="/public/image/downArrow.svg" alt="arrow" /> </div> </div> <ul class="optionList"> <li class="option">coffee</li> <li class="option">water</li> <li class="option">latte</li> <li class="option">jucie</li> </ul> </div> <div class="selectBox"> <div class="selected"> <div class="selected-value">food</div> <div class="arrow"> <img src="/public/image/downArrow.svg" alt="arrow" /> </div> </div> <ul class="optionList"> <li class="option">pizza</li> <li class="option">rice</li> <li class="option">burger</li> <li class="option">bread</li> </ul> </div> </section> <script> // 모든 셀렉션 박스 엘리먼트 선택 const selectBoxElements = document.querySelectorAll(".selectBox"); //.optionList function toggleSelectBox(selectBox) { selectBox.classList.toggle("active"); } // 옵션 선택 함수 / closest() - 가장 가까운 조상 function selectOption(optionElement) { const selectBox = optionElement.closest(".selectBox"); const selectedElement = selectBox.querySelector(".selected-value"); selectedElement.textContent = optionElement.textContent; } // 각 셀렉션 박스에 클릭 이벤트 리스너 추가 selectBoxElements.forEach((selectBoxElement) => { selectBoxElement.addEventListener("click", function (e) { const targetElement = e.target; const isOptionElement = targetElement.classList.contains("option"); if (isOptionElement) { selectOption(targetElement); } toggleSelectBox(selectBoxElement); }); }); // 문서 전체에 클릭 이벤트 리스너 추가 // 모든 셀렉션 박스 이외의 부분을 클릭했을 때, // 모든 셀렉션 박스에서 'active' 클래스를 제거하여 옵션 목록을 숨긴다. document.addEventListener("click", function (e) { const targetElement = e.target; const isSelect = targetElement.classList.contains("selectBox") || targetElement.closest(".selectBox"); if (isSelect) { return; } // 모든 셀렉션 박스에서 'active' 클래스 제거 const allSelectBoxElements = document.querySelectorAll(".selectBox"); allSelectBoxElements.forEach((boxElement) => { boxElement.classList.remove("active"); }); }); </script> </body> </html>
결과