Skip to content

Select

For picking exactly one from a fixed list — once there are more than about six options and vertical space matters.

Inputs

Live preview

Source

<div class="dc-sel">
  <label class="dc-sel__label" for="dc-sel-ship">배송 시간대</label>
  <span class="dc-sel__wrap">
    <select class="dc-sel__input" id="dc-sel-ship" name="ship" aria-describedby="dc-sel-ship-help">
      <option value="">선택해 주세요</option>
      <option value="am">오전 (09시~12시)</option>
      <option value="pm" selected>오후 (13시~18시)</option>
      <option value="night">저녁 (18시~21시)</option>
    </select>
    <svg class="dc-sel__icon" viewBox="0 0 20 20" width="18" height="18" aria-hidden="true" focusable="false"><path d="M5 8l5 5 5-5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /></svg>
  </span>
  <p class="dc-sel__help" id="dc-sel-ship-help">기사님 경로에 따라 30분 정도 차이가 날 수 있습니다.</p>
</div>
.dc-sel {
  display: flex; flex-direction: column; gap: var(--dc-2);
  max-width: 360px; font-family: var(--dc-font);
}
.dc-sel__label { font-size: 14px; font-weight: 600; color: var(--dc-text); }
.dc-sel__wrap { position: relative; display: block; }
.dc-sel__input {
  appearance: none; -webkit-appearance: none;
  width: 100%; min-height: 44px;
  padding: 0 calc(var(--dc-6) + var(--dc-2)) 0 var(--dc-3);
  border: 1px solid var(--dc-line-field); border-radius: var(--dc-r-sm);
  background: var(--dc-surface); color: var(--dc-text);
  font-family: inherit; font-size: 15px; line-height: 1.4;
  transition: border-color var(--dc-fast), box-shadow var(--dc-fast);
}
.dc-sel__input:hover { border-color: var(--dc-line-bold); }
.dc-sel__input:focus {
  outline: none; border-color: var(--dc-brand);
  box-shadow: 0 0 0 3px var(--dc-brand-soft);
}
.dc-sel__input[aria-invalid="true"] { border-color: var(--dc-danger); }
.dc-sel__input[disabled] {
  background: var(--dc-sunken); color: var(--dc-text-mute);
  border-color: var(--dc-line); cursor: not-allowed;
}
.dc-sel__icon {
  position: absolute; top: 50%; right: var(--dc-3);
  transform: translateY(-50%); pointer-events: none;
  color: var(--dc-text-sub);
}
.dc-sel__input[disabled] ~ .dc-sel__icon { color: var(--dc-text-mute); }
.dc-sel__help { margin: 0; font-size: 13px; line-height: 1.5; color: var(--dc-text-sub); }
.dc-sel__error {
  margin: 0; display: flex; align-items: flex-start; gap: var(--dc-1);
  font-size: 13px; font-weight: 600; line-height: 1.5; color: var(--dc-danger);
}
.dc-sel--sm .dc-sel__input { min-height: 36px; font-size: 14px; }

How to use it

  • Five options or fewer that people need to compare? Radios read better
  • Make the first option "Please choose", and preselect the real default when there is one
  • Group long lists with optgroup so they can be scanned

Watch out for

  • Replacing the native select with a custom listbox means rebuilding keyboard and screen-reader behaviour from scratch
  • Without right padding for the chevron, long option names run under the icon

Next