체크박스와 라디오

체크박스와 라디오 (Checks and radios)

완전히 다시 작성된 checks 컴포넌트로 일관된 크로스 브라우저·크로스 디바이스 체크박스와 라디오를 만들어 보아요.

출처: 문서

본문

접근 방식 (Approach)

브라우저 기본 체크박스와 라디오는 .form-check, 즉 두 입력 타입 모두를 위한 일련의 클래스의 도움으로 대체돼요. 이는 HTML 요소의 레이아웃과 동작을 개선하고, 더 큰 커스터마이즈와 크로스 브라우저 일관성을 제공해요. 체크박스는 목록에서 하나 또는 여러 옵션을 선택하기 위한 것이고, 라디오는 여러 옵션 중 하나를 선택하기 위한 것이에요.

구조적으로 우리의 <input>과 <label>은 <label> 안의 <input> 형태가 아니라 형제 요소(sibling elements)예요. 이는 <input>과 <label>을 연결하기 위해 id와 for 속성을 지정해야 하므로 조금 더 장황해요. 우리는 모든 <input> 상태(예: :checked 또는 :disabled)에 형제 셀렉터(~)를 사용해요. 이 것을 .form-check-label 클래스와 결합하면 <input>의 상태에 따라 각 항목의 텍스트를 쉽게 스타일링할 수 있어요.

우리의 checks는 선택됨(checked) 또는 불확정(indeterminate) 상태를 나타내기 위해 커스텀 Bootstrap 아이콘을 사용해요.

Checks

<div class="form-check">
  <input class="form-check-input" type="checkbox" value="" id="checkDefault">
  <label class="form-check-label" for="checkDefault">
    Default checkbox
  </label>
</div>
<div class="form-check">
  <input class="form-check-input" type="checkbox" value="" id="checkChecked" checked>
  <label class="form-check-label" for="checkChecked">
    Checked checkbox
  </label>
</div>

Indeterminate

체크박스는 JavaScript로 수동으로 설정할 때 :indeterminate 의사 클래스를 활용할 수 있어요 (지정할 수 있는 HTML 속성은 없어요).

<div class="form-check">
  <input class="form-check-input" type="checkbox" value="" id="checkIndeterminate">
  <label class="form-check-label" for="checkIndeterminate">
    Indeterminate checkbox
  </label>
</div>

Disabled

disabled 속성을 추가하면 연결된 <label>이 입력의 상태를 나타내도록 더 밝은 색상으로 자동 스타일링돼요.

<div class="form-check">
  <input class="form-check-input" type="checkbox" value="" id="checkIndeterminateDisabled" disabled>
  <label class="form-check-label" for="checkIndeterminateDisabled">
    Disabled indeterminate checkbox
  </label>
</div>
<div class="form-check">
  <input class="form-check-input" type="checkbox" value="" id="checkDisabled" disabled>
  <label class="form-check-label" for="checkDisabled">
    Disabled checkbox
  </label>
</div>
<div class="form-check">
  <input class="form-check-input" type="checkbox" value="" id="checkCheckedDisabled" checked disabled>
  <label class="form-check-label" for="checkCheckedDisabled">
    Disabled checked checkbox
  </label>
</div>

Radios

<div class="form-check">
  <input class="form-check-input" type="radio" name="radioDefault" id="radioDefault1">
  <label class="form-check-label" for="radioDefault1">
    Default radio
  </label>
</div>
<div class="form-check">
  <input class="form-check-input" type="radio" name="radioDefault" id="radioDefault2" checked>
  <label class="form-check-label" for="radioDefault2">
    Default checked radio
  </label>
</div>

Disabled

disabled 속성을 추가하면 연결된 <label>이 입력의 상태를 나타내도록 더 밝은 색상으로 자동 스타일링돼요.

<div class="form-check">
  <input class="form-check-input" type="radio" name="radioDisabled" id="radioDisabled" disabled>
  <label class="form-check-label" for="radioDisabled">
    Disabled radio
  </label>
</div>
<div class="form-check">
  <input class="form-check-input" type="radio" name="radioDisabled" id="radioCheckedDisabled" checked disabled>
  <label class="form-check-label" for="radioCheckedDisabled">
    Disabled checked radio
  </label>
</div>

Switches

스위치(switch)는 커스텀 체크박스의 마크업을 갖지만 .form-switch 클래스를 사용해 토글 스위치로 렌더링돼요. 이 역할을 지원하는 보조 기술에 컨트롤의 본질을 더 정확하게 전달하려면 role="switch"를 사용하는 것을 고려해 보세요. 오래된 보조 기술에서는 폴백으로 일반 체크박스로만 안내될 거예요. 스위치도 disabled 속성을 지원해요.

<div class="form-check form-switch">
  <input class="form-check-input" type="checkbox" role="switch" id="switchCheckDefault">
  <label class="form-check-label" for="switchCheckDefault">Default switch checkbox input</label>
</div>
<div class="form-check form-switch">
  <input class="form-check-input" type="checkbox" role="switch" id="switchCheckChecked" checked>
  <label class="form-check-label" for="switchCheckChecked">Checked switch checkbox input</label>
</div>
<div class="form-check form-switch">
  <input class="form-check-input" type="checkbox" role="switch" id="switchCheckDisabled" disabled>
  <label class="form-check-label" for="switchCheckDisabled">Disabled switch checkbox input</label>
</div>
<div class="form-check form-switch">
  <input class="form-check-input" type="checkbox" role="switch" id="switchCheckCheckedDisabled" checked disabled>
  <label class="form-check-label" for="switchCheckCheckedDisabled">Disabled checked switch checkbox input</label>
</div>

네이티브 스위치 (Native switches)

입력에 switch 속성을 추가해서 모바일 Safari(iOS 17.4+)의 스위치를 점진적으로 향상시킬 수 있어요. 네이티브 iOS 스위치처럼 스위치를 토글할 때 햅틱 피드백(haptic feedback)을 활성화해 줘요. Bootstrap에서 우리의 스위치는 모두 커스텀 스타일을 사용하므로 이 속성을 사용해도 스타일 변경은 없어요.

<div class="form-check form-switch">
  <input class="form-check-input" type="checkbox" value="" id="checkNativeSwitch" switch>
  <label class="form-check-label" for="checkNativeSwitch">
    Native switch haptics
  </label>
</div>

switch 속성에 대해 더 자세히 알고 싶다면 WebKit 블로그를 읽어 보세요. macOS와 iOS 모두의 Safari 17.4+는 HTML에 네이티브 스타일 스위치를 갖고 있으며, 다른 브라우저는 표준 체크박스 외형으로 폴백해요. 더 최신 버전의 Safari에서 비-Bootstrap 체크박스에 이 속성을 적용하면 네이티브 스위치로 렌더링돼요.

기본 (스택) (Default (stacked))

기본적으로 즉시 형제인 체크박스와 라디오는 .form-check로 세로로 쌓이고 적절히 간격이 지정돼요.

<div class="form-check">
  <input class="form-check-input" type="checkbox" value="" id="defaultCheck1">
  <label class="form-check-label" for="defaultCheck1">
    Default checkbox
  </label>
</div>
<div class="form-check">
  <input class="form-check-input" type="checkbox" value="" id="defaultCheck2" disabled>
  <label class="form-check-label" for="defaultCheck2">
    Disabled checkbox
  </label>
</div>
<div class="form-check">
  <input class="form-check-input" type="radio" name="exampleRadios" id="exampleRadios1" value="option1" checked>
  <label class="form-check-label" for="exampleRadios1">
    Default radio
  </label>
</div>
<div class="form-check">
  <input class="form-check-input" type="radio" name="exampleRadios" id="exampleRadios2" value="option2">
  <label class="form-check-label" for="exampleRadios2">
    Second default radio
  </label>
</div>
<div class="form-check">
  <input class="form-check-input" type="radio" name="exampleRadios" id="exampleRadios3" value="option3" disabled>
  <label class="form-check-label" for="exampleRadios3">
    Disabled radio
  </label>
</div>

인라인 (Inline)

.form-check-inline을 아무 .form-check에 추가해서 같은 가로 줄에 체크박스나 라디오를 묶을 수 있어요.

<div class="form-check form-check-inline">
  <input class="form-check-input" type="checkbox" id="inlineCheckbox1" value="option1">
  <label class="form-check-label" for="inlineCheckbox1">1</label>
</div>
<div class="form-check form-check-inline">
  <input class="form-check-input" type="checkbox" id="inlineCheckbox2" value="option2">
  <label class="form-check-label" for="inlineCheckbox2">2</label>
</div>
<div class="form-check form-check-inline">
  <input class="form-check-input" type="checkbox" id="inlineCheckbox3" value="option3" disabled>
  <label class="form-check-label" for="inlineCheckbox3">3 (disabled)</label>
</div>
<div class="form-check form-check-inline">
  <input class="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1">
  <label class="form-check-label" for="inlineRadio1">1</label>
</div>
<div class="form-check form-check-inline">
  <input class="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio2" value="option2">
  <label class="form-check-label" for="inlineRadio2">2</label>
</div>
<div class="form-check form-check-inline">
  <input class="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio3" value="option3" disabled>
  <label class="form-check-label" for="inlineRadio3">3 (disabled)</label>
</div>

반대 (Reverse)

.form-check-reverse 수정자 클래스로 체크박스, 라디오, 스위치를 반대쪽에 배치해요.

<div class="form-check form-check-reverse">
  <input class="form-check-input" type="checkbox" value="" id="reverseCheck1">
  <label class="form-check-label" for="reverseCheck1">
    Reverse checkbox
  </label>
</div>
<div class="form-check form-check-reverse">
  <input class="form-check-input" type="checkbox" value="" id="reverseCheck2" disabled>
  <label class="form-check-label" for="reverseCheck2">
    Disabled reverse checkbox
  </label>
</div>

<div class="form-check form-switch form-check-reverse">
  <input class="form-check-input" type="checkbox" id="switchCheckReverse">
  <label class="form-check-label" for="switchCheckReverse">Reverse switch checkbox input</label>
</div>

레이블 없이 (Without labels)

레이블 텍스트가 없는 체크박스와 라디오는 감싸는 .form-check를 생략해요. 보조 기술에 어떤 형태로든 접근 가능한 이름(예: aria-label 사용)을 여전히 제공해야 한다는 점을 기억하세요. 자세한 내용은 forms overview 접근성 섹션을 참조하세요.

<div>
  <input class="form-check-input" type="checkbox" id="checkboxNoLabel" value="" aria-label="...">
</div>

<div>
  <input class="form-check-input" type="radio" name="radioNoLabel" id="radioNoLabel1" value="" aria-label="...">
</div>

토글 버튼 (Toggle buttons)

<label> 요소에 .form-check-label 대신 .btn 스타일을 사용해 버튼처럼 보이는 체크박스와 라디오 버튼을 만들어요. 필요하다면 이 토글 버튼들을 버튼 그룹으로 추가로 묶을 수도 있어요.

체크박스 토글 버튼 (Checkbox toggle buttons)

<input type="checkbox" class="btn-check" id="btn-check" autocomplete="off">
<label class="btn btn-primary" for="btn-check">Single toggle</label>

<input type="checkbox" class="btn-check" id="btn-check-2" checked autocomplete="off">
<label class="btn btn-primary" for="btn-check-2">Checked</label>

<input type="checkbox" class="btn-check" id="btn-check-3" autocomplete="off" disabled>
<label class="btn btn-primary" for="btn-check-3">Disabled</label>
<input type="checkbox" class="btn-check" id="btn-check-4" autocomplete="off">
<label class="btn" for="btn-check-4">Single toggle</label>

<input type="checkbox" class="btn-check" id="btn-check-5" checked autocomplete="off">
<label class="btn" for="btn-check-5">Checked</label>

<input type="checkbox" class="btn-check" id="btn-check-6" autocomplete="off" disabled>
<label class="btn" for="btn-check-6">Disabled</label>

시각적으로 이 체크박스 토글 버튼은 button 플러그인 토글 버튼과 동일해요. 하지만 보조 기술에는 다르게 전달돼요: 체크박스 토글은 (외형과 관계없이 근본적으로 여전히 체크박스이므로) 화면 판독기에서 "checked"/"not checked"로 안내되는 반면, button 플러그인 토글 버튼은 "button"/"button pressed"로 안내돼요. 이 두 접근 방식 사이의 선택은 만드는 토글의 유형과, 체크박스나 실제 버튼으로 안내될 때 토글이 사용자에게 의미가 있는지 여부에 따라 달라져요.

라디오 토글 버튼 (Radio toggle buttons)

<input type="radio" class="btn-check" name="options" id="option1" autocomplete="off" checked>
<label class="btn btn-secondary" for="option1">Checked</label>

<input type="radio" class="btn-check" name="options" id="option2" autocomplete="off">
<label class="btn btn-secondary" for="option2">Radio</label>

<input type="radio" class="btn-check" name="options" id="option3" autocomplete="off" disabled>
<label class="btn btn-secondary" for="option3">Disabled</label>

<input type="radio" class="btn-check" name="options" id="option4" autocomplete="off">
<label class="btn btn-secondary" for="option4">Radio</label>
<input type="radio" class="btn-check" name="options-base" id="option5" autocomplete="off" checked>
<label class="btn" for="option5">Checked</label>

<input type="radio" class="btn-check" name="options-base" id="option6" autocomplete="off">
<label class="btn" for="option6">Radio</label>

<input type="radio" class="btn-check" name="options-base" id="option7" autocomplete="off" disabled>
<label class="btn" for="option7">Disabled</label>

<input type="radio" class="btn-check" name="options-base" id="option8" autocomplete="off">
<label class="btn" for="option8">Radio</label>

아웃라인 스타일 (Outlined styles)

다양한 .btn 변형(예: 여러 아웃라인 스타일)이 지원돼요.

<input type="checkbox" class="btn-check" id="btn-check-outlined" autocomplete="off">
<label class="btn btn-outline-primary" for="btn-check-outlined">Single toggle</label><br>

<input type="checkbox" class="btn-check" id="btn-check-2-outlined" checked autocomplete="off">
<label class="btn btn-outline-secondary" for="btn-check-2-outlined">Checked</label><br>

<input type="radio" class="btn-check" name="options-outlined" id="success-outlined" autocomplete="off" checked>
<label class="btn btn-outline-success" for="success-outlined">Checked success radio</label>

<input type="radio" class="btn-check" name="options-outlined" id="danger-outlined" autocomplete="off">
<label class="btn btn-outline-danger" for="danger-outlined">Danger radio</label>

CSS

Sass 변수 (Sass variables)

Checks용 변수:

scss/_variables.scss

$form-check-input-width:                  1em;
$form-check-min-height:                   $font-size-base * $line-height-base;
$form-check-padding-start:                $form-check-input-width + .5em;
$form-check-margin-bottom:                .125rem;
$form-check-label-color:                  null;
$form-check-label-cursor:                 null;
$form-check-transition:                   null;

$form-check-input-active-filter:          brightness(90%);

$form-check-input-bg:                     $input-bg;
$form-check-input-border:                 var(--#{$prefix}border-width) solid var(--#{$prefix}border-color);
$form-check-input-border-radius:          .25em;
$form-check-radio-border-radius:          50%;
$form-check-input-focus-border:           $input-focus-border-color;
$form-check-input-focus-box-shadow:       $focus-ring-box-shadow;

$form-check-input-checked-color:          $component-active-color;
$form-check-input-checked-bg-color:       $component-active-bg;
$form-check-input-checked-border-color:   $form-check-input-checked-bg-color;
$form-check-input-checked-bg-image:       url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path fill='none' stroke='#{$form-check-input-checked-color}' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/></svg>");
$form-check-radio-checked-bg-image:       url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='2' fill='#{$form-check-input-checked-color}'/></svg>");

$form-check-input-indeterminate-color:          $component-active-color;
$form-check-input-indeterminate-bg-color:       $component-active-bg;
$form-check-input-indeterminate-border-color:   $form-check-input-indeterminate-bg-color;
$form-check-input-indeterminate-bg-image:       url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path fill='none' stroke='#{$form-check-input-indeterminate-color}' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/></svg>");

$form-check-input-disabled-opacity:        .5;
$form-check-label-disabled-opacity:        $form-check-input-disabled-opacity;
$form-check-btn-check-disabled-opacity:    $btn-disabled-opacity;

$form-check-inline-margin-end:    1rem;

Switches용 변수:

scss/_variables.scss

$form-switch-color:               rgba($black, .25);
$form-switch-width:               2em;
$form-switch-padding-start:       $form-switch-width + .5em;
$form-switch-bg-image:            url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-color}'/></svg>");
$form-switch-border-radius:       $form-switch-width;
$form-switch-transition:          background-position .15s ease-in-out;

$form-switch-focus-color:         $input-focus-border-color;
$form-switch-focus-bg-image:      url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-focus-color}'/></svg>");

$form-switch-checked-color:       $component-active-color;
$form-switch-checked-bg-image:    url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-checked-color}'/></svg>");
$form-switch-checked-bg-position: right center;

더 알아보기 (Learn more)