웹 기능:
맞춤설정 가능한 <select>
기존의 네이티브 <select> 요소는 스타일을 지정하기 어려웠으며 일반 텍스트 옵션만 포함할 수 있었습니다. appearance: base-select 속성은 <select> 요소의 맞춤설정 가능한 상태를 선택하는 선언적 CSS 전용 방법을 제공합니다. 이를 통해 개발자는 이미지, SVG, 복잡한 레이아웃과 같은 리치 HTML 콘텐츠를 <option> 요소 내에 포함하면서도 네이티브 키보드 접근성과 양식 통합을 유지할 수 있습니다. 이 패턴을 사용하여 무겁고 맞춤 제작된 선택 구성요소를 표준 네이티브 요소로 대체합니다.
구현 방법
Customizable Select API를 사용하여 리치 미디어 선택 도구를 구현하려면 다음 단계를 따르세요.
- 기본 스타일 선택:
::picker(select)가상 요소를 사용하여<select>요소와 내부 선택 도구 모두에appearance: base-select를 적용합니다. 이렇게 하면<select>내부 콘텐츠의 브라우저 HTML 파서가 변경됩니다. - 버튼 콘텐츠 정의:
<select>내에서 표준<button>및<selectedcontent>요소를 사용하여 선택 도구가 닫혀 있을 때 표시되는 내용을 정의합니다.<selectedcontent>요소는 선택한 옵션의 콘텐츠를 자동으로 미러링합니다. 버튼에 현재 선택된 리치 콘텐츠를 표시하려면 이 속성이 필요합니다. - 옵션 내에서 리치 콘텐츠 사용: 이제
<option>태그 내에 이미지, SVG, 기타 HTML 태그를 배치할 수 있습니다. 이 API 이전에는 브라우저가<option>태그에서 태그를 제거하고 일반 텍스트만 렌더링했습니다. - 팝오버 스타일 지정:
::picker(select)가상 요소를 타겟팅하여 드롭다운 옵션 목록의 스타일을 지정합니다. 최상위 레이어에서 렌더링되므로z-index를 사용하지 않아도 됩니다. 옵션은 기본적으로 Anchor Positioning API를 사용하여 배치됩니다.
예시 코드: 리치 역할 선택 도구
<label for="role-picker">Select your role</label>
<select class="custom-select" name="role" id="role-picker">
<button>
<selectedcontent></selectedcontent> <!-- Mirrors the selected option's content automatically so you do not need JS to update the button -->
</button>
<!-- Define concise aria-label values on options whose mirrored rich content would otherwise read awkwardly as a concatenated string -->
<option value="frontend" aria-label="Frontend Developer">
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect>
</svg>
<div class="option-text">
<span class="option-title">Frontend Developer</span>
<span class="option-desc">React, Vue, CSS</span>
</div>
</option>
<option value="backend" aria-label="Backend Developer">
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<rect x="2" y="12" width="20" height="14" rx="2" ry="2"></rect>
</svg>
<div class="option-text">
<span class="option-title">Backend Developer</span>
<span class="option-desc">Node.js, Python</span>
</div>
</option>
</select>
select.custom-select,
select.custom-select::picker(select) {
appearance: base-select; /* MUST opt-in both the select and its picker to enable the customizable state, otherwise browser standard rendering applies */
}
select.custom-select {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 12px;
background-color: #1e293b;
border: 1px solid #334155;
border-radius: 8px;
color: #f1f5f9;
cursor: pointer;
}
select.custom-select::picker(select) {
background-color: #0f172a;
border: 1px solid #334155;
border-radius: 8px;
padding: 8px;
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5);
width: anchor-size(width); /* Uses Anchor Positioning API to keep the dropdown precisely aligned to the button trigger width */
}
select.custom-select option {
display: flex;
align-items: center;
gap: 12px;
padding: 10px;
border-radius: 4px;
cursor: pointer;
}
select.custom-select option:hover {
background-color: #1e293b;
}
/* Remove standard OS checkmark for base-select */
select.custom-select option::before {
display: none;
}
/* MANDATORY: Provide multiple visual indicators (e.g., prominent background color and bold title font) to communicate the checked state cleanly */
select.custom-select option:checked {
background-color: #3b82f6;
color: #ffffff;
}
select.custom-select option:checked .option-title {
font-weight: 700;
}
전략적 구현 및 권장사항
- 이전에는 무거운 JavaScript UI 프레임워크로만 가능했던 복잡한 옵션 레이아웃 (아이콘, 설명, 이미지)이 필요한 경우
appearance: base-select를 사용하세요. - 성능 지연이 발생하는 경우 임시 요소를 사용하지 마세요. 브라우저는 기본 키보드 포커스를 기본적으로 처리합니다.
- 최상위 레이어 렌더링을 고려합니다. 선택 도구는 최상위 레이어에서 렌더링되므로 페이지 콘텐츠의 상대적
z-index를 재정의합니다. - 권장사항:
.custom-select selectedcontent .option-desc { display: none; }의 스타일을 지정하여 버튼 상태에서 보조 세부정보 (예: 설명)가 너무 많은 공간을 차지하는 경우 숨깁니다. - 레이아웃 동작을 테스트합니다.
appearance: base-select를 설정하면 가장 긴 옵션 너비를 기준으로 선택 항목의 크기를 조정하는 기본 브라우저 동작이 삭제됩니다. 레이아웃 변경을 방지하려면 고정 너비를 설정하거나 flex/grid 제약 조건을 사용해야 할 수 있습니다. <select>에name속성과 연결된<label>가 있는지 확인합니다. 이렇게 하면 맞춤 UI를 사용하더라도 스크린 리더가 구성요소에 액세스할 수 있고 표준 양식 제출이 올바르게 작동합니다.- 옵션에 표준
value속성을 사용하여 양식 제출이 이전과 동일하게 작동하도록 합니다.
대체 전략
맞춤설정 가능한 <select>의 대체 및 브라우저 지원
아직 appearance: base-select를 지원하지 않는 브라우저의 경우 <select> 요소가 표준 운영체제 드롭다운으로 원활하게 다운그레이드됩니다.
- 텍스트가 아닌 콘텐츠 무시: 이전 브라우저는
<option>태그 내의 HTML 태그 (예:<svg>또는<div>)를 제거하고 텍스트 노드만 렌더링합니다.<option>의 텍스트 콘텐츠가 그 자체로 읽기 쉽고 의미가 있는지 확인합니다. - HTML 구조 처리: 표준 파서는
<select>내의<button>및<selectedcontent>태그를 무시하거나 잘못된 것으로 처리할 수 있습니다. 표준 텍스트를 읽을 수 있는 대체로 간주하는 경우 점진적 개선을 위해 무거운 JavaScript 폴리필이 반드시 필요한 것은 아닙니다.
document.addEventListener("DOMContentLoaded", () => {
// Check if browser supports base-select value
if (!CSS.supports("appearance", "base-select")) {
// Custom select overrides are not supported natively.
}
});