기본 콘텐츠로 건너뛰기

JavaScript로 시/도 · 시/군/구 2단 콤보박스 구현하기 (대한민국 행정구역 전체 데이터)

JavaScript로 시/도 · 시/군/구 2단 콤보박스 구현하기 (대한민국 행정구역 전체 데이터)

JavaScript로 시/도 · 시/군/구 2단 콤보박스 구현하기 (대한민국 행정구역 전체 데이터)

회원가입 폼이나 쇼핑몰 배송지 입력 화면을 만들다 보면, 시/도 선택 후 자동으로 시/군/구가 바뀌는 2단 콤보박스는 거의 필수 기능입니다.

이 글에서는 대한민국 행정구역(시/도, 시/군/구) 전체 데이터를 JavaScript 객체로 정의하고, 이 데이터를 활용해 바닐라 JavaScript만으로 2단 주소 콤보박스를 구현하는 방법을 정리합니다.


1. 시/도 · 시/군/구 2단 콤보박스 동작 예제

먼저 결과물이 어떻게 동작하는지 간단한 데모를 보겠습니다.

주소 선택 예제

실제 서비스에서는 이 콤보박스를 회원가입, 마이페이지 주소 관리, 주문/배송지 입력 등에 그대로 붙여서 사용할 수 있습니다.

2. 대한민국 행정구역 JavaScript 데이터 구조

기본 구조는 매우 단순합니다. 시/도 이름을 객체의 Key로, 해당 시/도 아래의 시/군/구 목록을 배열로 가지는 형태입니다.


const sigunguData = {
    "강원도": [
        "강릉시","고성군","동해시","삼척시","속초시","양구군","양양군",
        "영월군","원주시","인제군","정선군","철원군","춘천시","태백시",
        "평창군","홍천군","화천군","횡성군"
    ],
    "경기도": [
        "가평군","고양시 덕양구","고양시 일산동구","고양시 일산서구","과천시",
        "광명시","광주시","구리시","군포시","김포시","남양주시","동두천시",
        "부천시","성남시 분당구","성남시 수정구","성남시 중원구",
        "수원시 권선구","수원시 영통구","수원시 장안구","수원시 팔달구",
        "시흥시","안산시 단원구","안산시 상록구","안성시",
        "안양시 동안구","안양시 만안구","양주시","양평군","여주시","연천군",
        "오산시","용인시 기흥구","용인시 수지구","용인시 처인구",
        "의왕시","의정부시","이천시","파주시","평택시","포천시","하남시","화성시"
    ],
    "경상남도": [
        "거제시","거창군","고성군","김해시","남해군","밀양시","사천시",
        "산청군","양산시","의령군","진주시","창녕군",
        "창원시 마산합포구","창원시 마산회원구","창원시 성산구",
        "창원시 의창구","창원시 진해구",
        "통영시","하동군","함안군","함양군","합천군"
    ],
    "경상북도": [
        "경산시","경주시","고령군","구미시","군위군","김천시","문경시",
        "봉화군","상주시","성주군","안동시","영덕군","영양군",
        "영주시","영천시","예천군","울릉군","울진군","의성군",
        "청도군","청송군","칠곡군","포항시 남구","포항시 북구"
    ],
    "광주광역시": ["광산구","남구","동구","북구","서구"],
    "대구광역시": ["남구","달서구","달성군","동구","북구","서구","수성구","중구"],
    "대전광역시": ["대덕구","동구","서구","유성구","중구"],
    "부산광역시": [
        "강서구","금정구","기장군","남구","동구","동래구","부산진구",
        "북구","사상구","사하구","서구","수영구","연제구",
        "영도구","중구","해운대구"
    ],
    "서울특별시": [
        "강남구","강동구","강북구","강서구","관악구","광진구",
        "구로구","금천구","노원구","도봉구","동대문구","동작구",
        "마포구","서대문구","서초구","성동구","성북구",
        "송파구","양천구","영등포구","용산구",
        "은평구","종로구","중구","중랑구"
    ],
    "세종특별자치시": [],
    "울산광역시": ["남구","동구","북구","울주군","중구"],
    "인천광역시": [
        "강화군","계양구","남동구","동구","미추홀구","부평구",
        "서구","연수구","옹진군","중구"
    ],
    "전라남도": [
        "강진군","고흥군","곡성군","광양시","구례군","나주시",
        "담양군","목포시","무안군","보성군","순천시","신안군",
        "여수시","영광군","영암군","완도군","장성군","장흥군",
        "진도군","함평군","해남군","화순군"
    ],
    "전라북도": [
        "고창군","군산시","김제시","남원시","무주군","부안군",
        "순창군","완주군","익산시","임실군","장수군",
        "전주시 덕진구","전주시 완산구","정읍시","진안군"
    ],
    "제주특별자치도": ["서귀포시","제주시"],
    "충청남도": [
        "계룡시","공주시","금산군","논산시","당진시","보령시",
        "부여군","서산시","서천군","아산시","예산군",
        "천안시 동남구","천안시 서북구",
        "청양군","태안군","홍성군"
    ],
    "충청북도": [
        "괴산군","단양군","보은군","영동군","옥천군",
        "음성군","제천시","증평군","진천군",
        "청주시 상당구","청주시 서원구",
        "청주시 청원구","청주시 흥덕구",
        "충주시"
    ]
};
        
참고: 세종특별자치시는 법정 구(區) 없이 바로 동/읍/면 단계로 내려가기 때문에 시/군/구 단위까지만 쓰는 2단 콤보박스에서는 배열을 비워두고 예외적으로 처리하는 방식이 일반적입니다.

3. HTML + JavaScript로 2단 콤보박스 구현하기

위에서 정의한 sigunguData 객체를 활용해 시/도 선택 시 → 해당 시/군/구를 자동으로 채워 넣는 로직을 작성해 보겠습니다.

3-1. HTML: 콤보박스 기본 구조


<div class="form-container">
    <h3>주소 선택</h3>
    <select id="province-select" aria-label="시/도 선택">
        <option value="">시/도 선택</option>
    </select>

    <select id="sigungu-select" aria-label="시/군/구 선택">
        <option value="">시/군/구 선택</option>
    </select>
</div>
        

3-2. JavaScript: 시/도 초기화 + 시/군/구 동적 변경


/** 1. 시/도, 시/군/구 select 요소 가져오기 */
const provinceSelect = document.getElementById('province-select');
const sigunguSelect  = document.getElementById('sigungu-select');

/** 2. 시/도 콤보박스 초기화 */
function initProvinceSelect() {
    const provinces = Object.keys(sigunguData); // 시/도 목록 (Key)

    for (const province of provinces) {
        const option = new Option(province, province);
        provinceSelect.add(option);
    }
}

/** 3. 시/군/구 콤보박스 업데이트 */
function updateSigunguSelect(selectedProvince) {
    // 기존 옵션 초기화
    sigunguSelect.innerHTML = '<option value="">시/군/구 선택</option>';

    if (selectedProvince) {
        const cities = sigunguData[selectedProvince] || [];

        if (cities.length === 0) {
            // 세종특별자치시 등 하위 구가 없는 경우
            sigunguSelect.disabled = true;
        } else {
            sigunguSelect.disabled = false;

            for (const city of cities) {
                const option = new Option(city, city);
                sigunguSelect.add(option);
            }
        }
    } else {
        // "시/도 선택"으로 되돌아간 경우
        sigunguSelect.disabled = true;
    }
}

/** 4. 시/도 바뀔 때마다 시/군/구 갱신 */
provinceSelect.addEventListener('change', (event) => {
    const selectedProvince = event.target.value;
    updateSigunguSelect(selectedProvince);
});

/** 5. 페이지 로드 시 초기화 */
initProvinceSelect();
sigunguSelect.disabled = true; // 처음에는 비활성화
        
TIP: 실무에서는 선택된 값은 <form> submit 시 서버로 그대로 넘어가므로 name="province", name="sigungu" 와 같이 name 속성을 추가해 두는 것이 좋습니다.

4. 회원가입/배송지 폼에 적용할 때 실무 팁

  • 1) name 속성 추가 서버에서 바로 활용할 수 있도록 <select name="province" id="province-select">, <select name="sigungu" id="sigungu-select"> 처럼 지정하세요.
  • 2) 기본값(기존 주소) 세팅 마이페이지에서 기존 주소 수정 화면이라면, initProvinceSelect() 후에 provinceSelect.value = '서울특별시'; updateSigunguSelect('서울특별시'); sigunguSelect.value = '강남구'; 와 같이 기존 값을 미리 선택해 줄 수 있습니다.
  • 3) 3단 콤보(시/도 → 시/군/구 → 동/읍/면) 동일한 패턴으로 객체 구조를 한 단계 더 늘리면 동/읍/면까지 3단 콤보박스로 확장 가능합니다.
  • 4) jQuery와 혼용 여부 이 글의 코드는 Vanilla JavaScript 기준이며, jQuery를 사용 중이어도 그대로 함께 사용 가능합니다.

5. 자주 묻는 질문 (FAQ)

Q1. 세종특별자치시의 배열이 빈 배열인 이유는?

세종시는 법정 구 없이 동/읍/면으로 바로 내려가기 때문에 “시/도 → 시/군/구” 2단 구조에서는 별도의 하위 행정구역을 넣지 않고 빈 배열로 두었습니다. 동/읍/면까지 처리해야 한다면 3단 콤보박스로 확장하는 것이 좋습니다.

Q2. 행정구역이 바뀌면 어떻게 업데이트하나요?

행정구역 조정(구 신설/통합 등)이 발생하면 sigunguData 객체의 해당 시/도 배열만 수정하면 됩니다. 데이터 레이어와 UI 로직을 분리해 두었기 때문에 유지보수가 비교적 쉽습니다.

Q3. 시/도 순서를 정렬해서 보여주고 싶어요.

Object.keys(sigunguData)로 가져온 배열은 선언 순서를 따르지만, provinces.sort() 등을 사용해 가나다순 정렬 후 옵션을 추가하면 됩니다.


이 글에서 소개한 시/도 · 시/군/구 2단 콤보박스 패턴은 대부분의 한국형 웹 서비스에서 재활용 가능한 기본 컴포넌트입니다. 프로젝트에 맞게 스타일(CSS)과 데이터 구조를 약간만 커스터마이징해서 사용해 보세요.

댓글

이 블로그의 인기 게시물

Java Servlet Request Parameter 완전 정복 — GET/POST 모든 파라미터 확인 & 디버깅 예제 (Request Parameter 전체보기)

Java Servlet Request Parameter 완전 정복 — GET/POST 모든 파라미터 확인 & 디버깅 예제 Java Servlet Request Parameter 완전 정복 웹 애플리케이션에서 클라이언트로부터 전달되는 Request Parameter 를 확인하는 것은 필수입니다. 이 글에서는 Java Servlet 과 JSP 에서 GET/POST 요청 파라미터를 전체 출력하고 디버깅하는 방법을 다양한 예제와 함께 소개합니다. 1. 기본 예제: getParameterNames() 사용 Enumeration<String> params = request.getParameterNames(); System.out.println("----------------------------"); while (params.hasMoreElements()){ String name = params.nextElement(); System.out.println(name + " : " + request.getParameter(name)); } System.out.println("----------------------------"); 위 코드는 요청에 포함된 모든 파라미터 이름과 값을 출력하는 기본 방법입니다. 2. HTML Form과 연동 예제 <form action="CheckParamsServlet" method="post"> 이름: <input type="text" name="username"><br> 이메일: <input type="email" name="email"><b...

PostgreSQL 달력(일별,월별)

SQL 팁: GENERATE_SERIES로 일별, 월별 날짜 목록 만들기 SQL 팁: GENERATE_SERIES 로 일별, 월별 날짜 목록 만들기 데이터베이스에서 통계 리포트를 작성하거나 비어있는 날짜 데이터를 채워야 할 때, 특정 기간의 날짜 목록이 필요할 수 있습니다. PostgreSQL과 같은 데이터베이스에서는 GENERATE_SERIES 함수를 사용하여 이 작업을 매우 간단하게 처리할 수 있습니다. 1. 🗓️ 일별 날짜 목록 생성하기 2020년 1월 1일부터 12월 31일까지의 모든 날짜를 '1 day' 간격으로 생성하는 쿼리입니다. WITH date_series AS ( SELECT DATE(GENERATE_SERIES( TO_DATE('2020-01-01', 'YYYY-MM-DD'), TO_DATE('2020-12-31', 'YYYY-MM-DD'), '1 day' )) AS DATE ) SELECT DATE FROM date_series 이 쿼리는 WITH 절(CTE)을 사용하여 date_series 라는 임시 테이블을 만들고, GENERATE_SERIES 함수로 날짜를 채웁니다. 결과 (일별 출력) 2. 📅 월별 날짜 목록 생성하기 동일한 원리로, 간격을 '1 MONTH' 로 변경하면 월별 목록을 생성할 수 있습니다. TO...

CSS로 레이어 팝업 화면 가운데 정렬하는 방법 (top·left·transform 완전 정리)

레이어 팝업 센터 정렬, 이 코드만 알면 끝 (CSS 예제 포함) 이벤트 배너나 공지사항을 띄울 때 레이어 팝업(center 정렬) 을 깔끔하게 잡는 게 생각보다 어렵습니다. 화면 크기가 변해도 가운데에 고정되고, 모바일에서도 자연스럽게 보이게 하려면 position , top , left , transform 을 정확하게 이해해야 합니다. 이 글에서는 아래 내용을 예제로 정리합니다. 레이어 팝업(center 정렬)의 기본 개념 자주 사용하는 position: absolute / fixed 정렬 방식 질문에서 주신 스타일 top: 3.25%; left: 50%; transform: translateX(-50%) 의 의미 실무에서 바로 쓰는 반응형 레이어 팝업 HTML/CSS 예제 1. 레이어 팝업(center 정렬)이란? 레이어 팝업(레이어 팝업창) 은 새 창을 띄우는 것이 아니라, 현재 페이지 위에 div 레이어를 띄워서 공지사항, 광고, 이벤트 등을 보여주는 방식을 말합니다. 검색엔진(SEO) 입장에서도 같은 페이지 안에 HTML이 존재 하기 때문에 팝업 안의 텍스트도 정상적으로 인덱싱될 수 있습니다. 즉, “레이어 팝업 센터 정렬”, “레이어 팝업 만드는 방법”과 같이 관련 키워드를 적절히 넣어주면 검색 노출에 도움이 됩니다. 2. 질문에서 주신 레이어 팝업 스타일 분석 질문에서 주신 스타일은 다음과 같습니다. <div class="layer-popup" style="width:1210px; z-index:9001; position:absolute; top:3.25%; left:50%; transform:translateX(-50%);"> 레이어 팝업 내용 <...