폼

폼 (Forms)

다양한 폼을 만들기 위한 폼 컨트롤 스타일, 레이아웃 옵션, 커스텀 컴포넌트의 예시와 사용 지침이에요.

출처: 문서

본문

  • Form control — 여러 상태를 지원하는 텍스트 입력과 텍스트 영역을 스타일링해요.
  • Select — 브라우저 기본 셀렉트 요소를 커스텀 초기 외형으로 개선해요.
  • Checks & radios — 입력 옵션 선택을 위해 커스텀 라디오 버튼과 체크박스를 폼에서 사용해요.
  • Range — 브라우저 기본 범위 입력을 커스텀 버전으로 교체해요.
  • Input group — 의미론적 가치를 높이기 위해 라벨과 버튼을 입력에 부착해요.
  • Floating labels — 입력 필드 위로 떠오르는 아름답고 단순한 폼 라벨을 만들어요.
  • Layout — 폼으로 인라인, 수평, 복잡한 그리드 기반 레이아웃을 만들어요.
  • Validation — 커스텀 또는 네이티브 검증 동작과 스타일로 폼을 검증해요.

개요 (Overview)

Bootstrap의 폼 컨트롤은 Reboot된 폼 스타일을 클래스로 확장해요. 이 클래스들을 사용해 커스터마이즈된 디스플레이를 선택해서 브라우저와 기기 전반에 걸쳐 더 일관된 렌더링을 얻을 수 있어요.

이메일 검증, 숫자 선택 등의 최신 입력 컨트롤을 활용하려면 모든 입력에 적절한 type 속성을 사용해야 해요 (예: 이메일 주소는 email, 숫자 정보는 number).

다음은 Bootstrap의 폼 스타일을 보여주는 빠른 예시예요. 필요 클래스, 폼 레이아웃 등에 대한 문서를 계속 읽어 보세요.

<form>
  <div class="mb-3">
    <label for="exampleInputEmail1" class="form-label">Email address</label>
    <input type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp">
    <div id="emailHelp" class="form-text">We'll never share your email with anyone else.</div>
  </div>
  <div class="mb-3">
    <label for="exampleInputPassword1" class="form-label">Password</label>
    <input type="password" class="form-control" id="exampleInputPassword1">
  </div>
  <div class="mb-3 form-check">
    <input type="checkbox" class="form-check-input" id="exampleCheck1">
    <label class="form-check-label" for="exampleCheck1">Check me out</label>
  </div>
  <button type="submit" class="btn btn-primary">Submit</button>
</form>

비활성화 폼 (Disabled forms)

입력에 disabled 불리언 속성을 추가하면 사용자 상호작용을 막고 더 밝게 보이게 해요.

<input class="form-control" id="disabledInput" type="text" placeholder="Disabled input here..." disabled>

<fieldset>에 disabled 속성을 추가하면 안의 모든 컨트롤을 비활성화해요. 브라우저는 <fieldset disabled> 안의 모든 네이티브 폼 컨트롤(<input>, <select>, <button> 요소)을 비활성화된 것으로 취급해서 키보드와 마우스 상호작용을 모두 막아요.

하지만 폼에 <a class="btn btn-*">...</a> 같은 커스텀 버튼형 요소도 포함한다면, 이들은 pointer-events: none 스타일만 받게 되어 여전히 키보드로 포커스하고 조작할 수 있어요. 이 경우 tabindex="-1"을 추가해 포커스를 받지 못하게 하고, aria-disabled="disabled"를 사용해 상태를 보조 기술에 알리는 방식으로 이러한 컨트롤을 수동으로 수정해야 해요.

<form>
  <fieldset disabled>
    <legend>Disabled fieldset example</legend>
    <div class="mb-3">
      <label for="disabledTextInput" class="form-label">Disabled input</label>
      <input type="text" id="disabledTextInput" class="form-control" placeholder="Disabled input">
    </div>
    <div class="mb-3">
      <label for="disabledSelect" class="form-label">Disabled select menu</label>
      <select id="disabledSelect" class="form-select">
        <option>Disabled select</option>
      </select>
    </div>
    <div class="mb-3">
      <div class="form-check">
        <input class="form-check-input" type="checkbox" id="disabledFieldsetCheck" disabled>
        <label class="form-check-label" for="disabledFieldsetCheck">
          Can’t check this
        </label>
      </div>
    </div>
    <button type="submit" class="btn btn-primary">Submit</button>
  </fieldset>
</form>

접근성 (Accessibility)

모든 폼 컨트롤에 적절한 접근 가능한 이름이 있어서 그 목적이 보조 기술 사용자에게 전달될 수 있도록 해야 해요. 이를 달성하는 가장 간단한 방법은 <label> 요소를 사용하거나—버튼의 경우—<button>...</button> 내용의 일부로 충분히 설명적인 텍스트를 포함하는 거예요.

보이는 <label>이나 적절한 텍스트 내용을 포함할 수 없는 상황에서는 접근 가능한 이름을 제공하는 다른 방법이 있어요:

  • .visually-hidden 클래스로 숨겨진 <label> 요소
  • aria-labelledby로 라벨 역할을 할 수 있는 기존 요소를 가리키기
  • title 속성 제공하기
  • aria-label로 요소의 접근 가능한 이름을 명시적으로 설정하기

이 중 아무것도 없으면 보조 기술은 <input>과 <textarea> 요소의 placeholder 속성을 접근 가능한 이름의 폴백으로 사용할 수 있어요. 이 섹션의 예시는 몇 가지 제안된 사례별 접근 방식을 제공해요.

시각적으로 숨겨진 콘텐츠(.visually-hidden, aria-label, 심지어 폼 필드에 내용이 생기면 사라지는 placeholder 콘텐츠까지)를 사용하는 것은 보조 기술 사용자에게 이점이 있지만, 보이는 라벨 텍스트의 부족은 특정 사용자에게 여전히 문제가 될 수 있어요. 어떤 형태의 보이는 라벨이 일반적으로 접근성과 사용성 모두에서 가장 좋은 접근 방식이에요.

CSS

많은 폼 변수는 개별 폼 컴포넌트에서 재사용하고 확장할 수 있도록 일반 수준에서 설정돼요. 이를 가장 흔히 $input-btn-*와 $input-* 변수로 보게 될 거예요.

Sass 변수 (Sass variables)

$input-btn-* 변수는 버튼과 폼 컴포넌트 사이의 공유 전역 변수예요. 이 변수들이 다른 컴포넌트별 변수의 값으로 자주 재할당되는 것을 볼 수 있어요.

scss/_variables.scss

$input-btn-padding-y:         .375rem;
$input-btn-padding-x:         .75rem;
$input-btn-font-family:       null;
$input-btn-font-size:         $font-size-base;
$input-btn-line-height:       $line-height-base;

$input-btn-focus-width:         $focus-ring-width;
$input-btn-focus-color-opacity: $focus-ring-opacity;
$input-btn-focus-color:         $focus-ring-color;
$input-btn-focus-blur:          $focus-ring-blur;
$input-btn-focus-box-shadow:    $focus-ring-box-shadow;

$input-btn-padding-y-sm:      .25rem;
$input-btn-padding-x-sm:      .5rem;
$input-btn-font-size-sm:      $font-size-sm;

$input-btn-padding-y-lg:      .5rem;
$input-btn-padding-x-lg:      1rem;
$input-btn-font-size-lg:      $font-size-lg;

$input-btn-border-width:      var(--#{$prefix}border-width);

더 알아보기 (Learn more)