주요 콘텐츠로 건너뛰기 문서 탐색으로 건너뛰기
in English

확인

브라우저 기본 동작 또는 사용자 정의 스타일 및 JavaScript를 통해 HTML5 양식 유효성 검사를 통해 사용자에게 가치 있고 실행 가능한 피드백을 제공하십시오.

현재 클라이언트 측 사용자 지정 유효성 검사 스타일 및 도구 설명은 보조 기술에 노출되지 않기 때문에 액세스할 수 없다는 것을 알고 있습니다. 솔루션을 개발하는 동안 서버 측 옵션이나 기본 브라우저 유효성 검사 방법을 사용하는 것이 좋습니다.

작동 방식

부트스트랩에서 양식 유효성 검사가 작동하는 방식은 다음과 같습니다.

  • HTML 양식 유효성 검사는 CSS의 두 의사 클래스 :invalid:valid. <input>, <select><textarea>요소 에 적용됩니다 .
  • 부트스트랩 범위 :invalid:valid스타일은 .was-validated일반적으로 <form>. 그렇지 않으면 값이 없는 모든 필수 필드는 페이지 로드 시 유효하지 않은 것으로 표시됩니다. 이렇게 하면 활성화 시기를 선택할 수 있습니다(일반적으로 양식 제출이 시도된 후).
  • 양식의 모양을 재설정하려면(예: AJAX를 사용한 동적 양식 제출의 경우) 제출 후 다시 .was-validated클래스를 제거하십시오.<form>
  • 대안으로, .is-invalid서버 측 유효성 검사.is-valid 를 위해 의사 클래스 대신 클래스를 사용할 수 있습니다 . 부모 클래스 가 필요하지 않습니다 ..was-validated
  • <label>CSS 작동 방식의 제약으로 인해 사용자 정의 JavaScript의 도움 없이 DOM의 양식 컨트롤 앞에 오는 스타일을 (현재) 적용할 수 없습니다 .
  • 모든 최신 브라우저는 양식 컨트롤의 유효성을 검사하기 위한 일련의 JavaScript 메서드인 제약 조건 유효성 검사 API 를 지원합니다.
  • 피드백 메시지는 브라우저 기본값 (브라우저마다 다르며 CSS를 통해 스타일이 지정되지 않음) 또는 추가 HTML 및 CSS가 포함된 사용자 정의 피드백 스타일을 사용할 수 있습니다.
  • setCustomValidityJavaScript에서 사용자 정의 유효성 메시지를 제공할 수 있습니다 .

이를 염두에 두고 사용자 정의 양식 유효성 검사 스타일, 선택적 서버 측 클래스 및 브라우저 기본값에 대한 다음 데모를 고려하십시오.

사용자 정의 스타일

사용자 지정 부트스트랩 양식 유효성 검사 메시지의 경우 novalidate부울 속성을 <form>. 이렇게 하면 브라우저 기본 피드백 도구 설명이 비활성화되지만 JavaScript의 양식 유효성 검사 API에 대한 액세스는 계속 제공됩니다. 아래 양식을 제출해 보십시오. JavaScript가 제출 버튼을 가로채서 피드백을 전달합니다. 제출을 시도하면 양식 컨트롤에 적용된 :invalid및 스타일이 표시됩니다.:valid

사용자 정의 피드백 스타일은 사용자 정의 색상, 테두리, 초점 스타일 및 배경 아이콘을 적용하여 피드백을 더 잘 전달합니다. s의 배경 아이콘 <select>은 에서만 사용할 수 있으며 에서는 사용할 수 .form-select없습니다 .form-control.

Looks good!
Looks good!
@
Please choose a username.
Please provide a valid city.
Please select a valid state.
Please provide a valid zip.
You must agree before submitting.
<form class="row g-3 needs-validation" novalidate>
  <div class="col-md-4">
    <label for="validationCustom01" class="form-label">First name</label>
    <input type="text" class="form-control" id="validationCustom01" value="Mark" required>
    <div class="valid-feedback">
      Looks good!
    </div>
  </div>
  <div class="col-md-4">
    <label for="validationCustom02" class="form-label">Last name</label>
    <input type="text" class="form-control" id="validationCustom02" value="Otto" required>
    <div class="valid-feedback">
      Looks good!
    </div>
  </div>
  <div class="col-md-4">
    <label for="validationCustomUsername" class="form-label">Username</label>
    <div class="input-group has-validation">
      <span class="input-group-text" id="inputGroupPrepend">@</span>
      <input type="text" class="form-control" id="validationCustomUsername" aria-describedby="inputGroupPrepend" required>
      <div class="invalid-feedback">
        Please choose a username.
      </div>
    </div>
  </div>
  <div class="col-md-6">
    <label for="validationCustom03" class="form-label">City</label>
    <input type="text" class="form-control" id="validationCustom03" required>
    <div class="invalid-feedback">
      Please provide a valid city.
    </div>
  </div>
  <div class="col-md-3">
    <label for="validationCustom04" class="form-label">State</label>
    <select class="form-select" id="validationCustom04" required>
      <option selected disabled value="">Choose...</option>
      <option>...</option>
    </select>
    <div class="invalid-feedback">
      Please select a valid state.
    </div>
  </div>
  <div class="col-md-3">
    <label for="validationCustom05" class="form-label">Zip</label>
    <input type="text" class="form-control" id="validationCustom05" required>
    <div class="invalid-feedback">
      Please provide a valid zip.
    </div>
  </div>
  <div class="col-12">
    <div class="form-check">
      <input class="form-check-input" type="checkbox" value="" id="invalidCheck" required>
      <label class="form-check-label" for="invalidCheck">
        Agree to terms and conditions
      </label>
      <div class="invalid-feedback">
        You must agree before submitting.
      </div>
    </div>
  </div>
  <div class="col-12">
    <button class="btn btn-primary" type="submit">Submit form</button>
  </div>
</form>
// Example starter JavaScript for disabling form submissions if there are invalid fields
(function () {
  'use strict'

  // Fetch all the forms we want to apply custom Bootstrap validation styles to
  var forms = document.querySelectorAll('.needs-validation')

  // Loop over them and prevent submission
  Array.prototype.slice.call(forms)
    .forEach(function (form) {
      form.addEventListener('submit', function (event) {
        if (!form.checkValidity()) {
          event.preventDefault()
          event.stopPropagation()
        }

        form.classList.add('was-validated')
      }, false)
    })
})()

브라우저 기본값

사용자 지정 유효성 검사 피드백 메시지 또는 양식 동작을 변경하기 위해 JavaScript를 작성하는 데 관심이 없으십니까? 좋습니다. 브라우저 기본값을 사용할 수 있습니다. 아래 양식을 제출해 보세요. 브라우저와 OS에 따라 약간 다른 스타일의 피드백이 표시됩니다.

이러한 피드백 스타일은 CSS로 스타일을 지정할 수 없지만 JavaScript를 통해 피드백 텍스트를 사용자 정의할 수 있습니다.

@
<form class="row g-3">
  <div class="col-md-4">
    <label for="validationDefault01" class="form-label">First name</label>
    <input type="text" class="form-control" id="validationDefault01" value="Mark" required>
  </div>
  <div class="col-md-4">
    <label for="validationDefault02" class="form-label">Last name</label>
    <input type="text" class="form-control" id="validationDefault02" value="Otto" required>
  </div>
  <div class="col-md-4">
    <label for="validationDefaultUsername" class="form-label">Username</label>
    <div class="input-group">
      <span class="input-group-text" id="inputGroupPrepend2">@</span>
      <input type="text" class="form-control" id="validationDefaultUsername"  aria-describedby="inputGroupPrepend2" required>
    </div>
  </div>
  <div class="col-md-6">
    <label for="validationDefault03" class="form-label">City</label>
    <input type="text" class="form-control" id="validationDefault03" required>
  </div>
  <div class="col-md-3">
    <label for="validationDefault04" class="form-label">State</label>
    <select class="form-select" id="validationDefault04" required>
      <option selected disabled value="">Choose...</option>
      <option>...</option>
    </select>
  </div>
  <div class="col-md-3">
    <label for="validationDefault05" class="form-label">Zip</label>
    <input type="text" class="form-control" id="validationDefault05" required>
  </div>
  <div class="col-12">
    <div class="form-check">
      <input class="form-check-input" type="checkbox" value="" id="invalidCheck2" required>
      <label class="form-check-label" for="invalidCheck2">
        Agree to terms and conditions
      </label>
    </div>
  </div>
  <div class="col-12">
    <button class="btn btn-primary" type="submit">Submit form</button>
  </div>
</form>

서버 측

클라이언트 측 유효성 검사를 사용하는 것이 좋지만 서버 측 유효성 검사가 필요한 경우 및 를 사용하여 유효하지 않고 유효한 양식 필드를 나타낼 수 .is-invalid있습니다 .is-valid. 이러한 .invalid-feedback클래스에서도 지원됩니다.

유효하지 않은 필드의 경우 유효하지 않은 피드백/오류 메시지가 다음을 사용하여 관련 양식 필드와 연결되어 있는지 확인하십시오 ( 필드가 이미 추가 양식 텍스트를 가리키는 경우 aria-describedby이 속성은 둘 이상의 참조를 허용한다는 점에 유의 ).id

테두리 반경 문제 를 해결하려면 입력 그룹에 추가 .has-validation클래스가 필요합니다.

좋아 보인다!
좋아 보인다!
@
사용자 이름을 선택하세요.
유효한 도시를 입력하세요.
유효한 상태를 선택하십시오.
유효한 우편번호를 입력하세요.
제출하기 전에 동의해야 합니다.
<form class="row g-3">
  <div class="col-md-4">
    <label for="validationServer01" class="form-label">First name</label>
    <input type="text" class="form-control is-valid" id="validationServer01" value="Mark" required>
    <div class="valid-feedback">
      Looks good!
    </div>
  </div>
  <div class="col-md-4">
    <label for="validationServer02" class="form-label">Last name</label>
    <input type="text" class="form-control is-valid" id="validationServer02" value="Otto" required>
    <div class="valid-feedback">
      Looks good!
    </div>
  </div>
  <div class="col-md-4">
    <label for="validationServerUsername" class="form-label">Username</label>
    <div class="input-group has-validation">
      <span class="input-group-text" id="inputGroupPrepend3">@</span>
      <input type="text" class="form-control is-invalid" id="validationServerUsername" aria-describedby="inputGroupPrepend3 validationServerUsernameFeedback" required>
      <div id="validationServerUsernameFeedback" class="invalid-feedback">
        Please choose a username.
      </div>
    </div>
  </div>
  <div class="col-md-6">
    <label for="validationServer03" class="form-label">City</label>
    <input type="text" class="form-control is-invalid" id="validationServer03" aria-describedby="validationServer03Feedback" required>
    <div id="validationServer03Feedback" class="invalid-feedback">
      Please provide a valid city.
    </div>
  </div>
  <div class="col-md-3">
    <label for="validationServer04" class="form-label">State</label>
    <select class="form-select is-invalid" id="validationServer04" aria-describedby="validationServer04Feedback" required>
      <option selected disabled value="">Choose...</option>
      <option>...</option>
    </select>
    <div id="validationServer04Feedback" class="invalid-feedback">
      Please select a valid state.
    </div>
  </div>
  <div class="col-md-3">
    <label for="validationServer05" class="form-label">Zip</label>
    <input type="text" class="form-control is-invalid" id="validationServer05" aria-describedby="validationServer05Feedback" required>
    <div id="validationServer05Feedback" class="invalid-feedback">
      Please provide a valid zip.
    </div>
  </div>
  <div class="col-12">
    <div class="form-check">
      <input class="form-check-input is-invalid" type="checkbox" value="" id="invalidCheck3" aria-describedby="invalidCheck3Feedback" required>
      <label class="form-check-label" for="invalidCheck3">
        Agree to terms and conditions
      </label>
      <div id="invalidCheck3Feedback" class="invalid-feedback">
        You must agree before submitting.
      </div>
    </div>
  </div>
  <div class="col-12">
    <button class="btn btn-primary" type="submit">Submit form</button>
  </div>
</form>

지원되는 요소

유효성 검사 스타일은 다음 양식 컨트롤 및 구성 요소에 사용할 수 있습니다.

  • <input>s 및 <textarea>s with ( 입력 그룹에 .form-control최대 1개 포함 ).form-control
  • <select>.form-select
  • .form-check에스
텍스트 영역에 메시지를 입력하세요.
잘못된 피드백 텍스트의 예
잘못된 피드백 텍스트 추가 예시
잘못된 선택 피드백의 예
잘못된 양식 파일 피드백의 예
<form class="was-validated">
  <div class="mb-3">
    <label for="validationTextarea" class="form-label">Textarea</label>
    <textarea class="form-control is-invalid" id="validationTextarea" placeholder="Required example textarea" required></textarea>
    <div class="invalid-feedback">
      Please enter a message in the textarea.
    </div>
  </div>

  <div class="form-check mb-3">
    <input type="checkbox" class="form-check-input" id="validationFormCheck1" required>
    <label class="form-check-label" for="validationFormCheck1">Check this checkbox</label>
    <div class="invalid-feedback">Example invalid feedback text</div>
  </div>

  <div class="form-check">
    <input type="radio" class="form-check-input" id="validationFormCheck2" name="radio-stacked" required>
    <label class="form-check-label" for="validationFormCheck2">Toggle this radio</label>
  </div>
  <div class="form-check mb-3">
    <input type="radio" class="form-check-input" id="validationFormCheck3" name="radio-stacked" required>
    <label class="form-check-label" for="validationFormCheck3">Or toggle this other radio</label>
    <div class="invalid-feedback">More example invalid feedback text</div>
  </div>

  <div class="mb-3">
    <select class="form-select" required aria-label="select example">
      <option value="">Open this select menu</option>
      <option value="1">One</option>
      <option value="2">Two</option>
      <option value="3">Three</option>
    </select>
    <div class="invalid-feedback">Example invalid select feedback</div>
  </div>

  <div class="mb-3">
    <input type="file" class="form-control" aria-label="file example" required>
    <div class="invalid-feedback">Example invalid form file feedback</div>
  </div>

  <div class="mb-3">
    <button class="btn btn-primary" type="submit" disabled>Submit form</button>
  </div>
</form>

툴팁

양식 레이아웃에서 허용하는 경우 스타일이 지정된 도구 설명에 유효성 검사 피드백을 표시 하도록 .{valid|invalid}-feedback클래스를 클래스로 바꿀 수 있습니다 . 툴팁 위치 지정을 위해 .{valid|invalid}-tooltip부모가 있어야 합니다 . position: relative아래 예에서 열 클래스에는 이미 이 항목이 있지만 프로젝트에 다른 설정이 필요할 수 있습니다.

Looks good!
Looks good!
@
Please choose a unique and valid username.
Please provide a valid city.
Please select a valid state.
Please provide a valid zip.
<form class="row g-3 needs-validation" novalidate>
  <div class="col-md-4 position-relative">
    <label for="validationTooltip01" class="form-label">First name</label>
    <input type="text" class="form-control" id="validationTooltip01" value="Mark" required>
    <div class="valid-tooltip">
      Looks good!
    </div>
  </div>
  <div class="col-md-4 position-relative">
    <label for="validationTooltip02" class="form-label">Last name</label>
    <input type="text" class="form-control" id="validationTooltip02" value="Otto" required>
    <div class="valid-tooltip">
      Looks good!
    </div>
  </div>
  <div class="col-md-4 position-relative">
    <label for="validationTooltipUsername" class="form-label">Username</label>
    <div class="input-group has-validation">
      <span class="input-group-text" id="validationTooltipUsernamePrepend">@</span>
      <input type="text" class="form-control" id="validationTooltipUsername" aria-describedby="validationTooltipUsernamePrepend" required>
      <div class="invalid-tooltip">
        Please choose a unique and valid username.
      </div>
    </div>
  </div>
  <div class="col-md-6 position-relative">
    <label for="validationTooltip03" class="form-label">City</label>
    <input type="text" class="form-control" id="validationTooltip03" required>
    <div class="invalid-tooltip">
      Please provide a valid city.
    </div>
  </div>
  <div class="col-md-3 position-relative">
    <label for="validationTooltip04" class="form-label">State</label>
    <select class="form-select" id="validationTooltip04" required>
      <option selected disabled value="">Choose...</option>
      <option>...</option>
    </select>
    <div class="invalid-tooltip">
      Please select a valid state.
    </div>
  </div>
  <div class="col-md-3 position-relative">
    <label for="validationTooltip05" class="form-label">Zip</label>
    <input type="text" class="form-control" id="validationTooltip05" required>
    <div class="invalid-tooltip">
      Please provide a valid zip.
    </div>
  </div>
  <div class="col-12">
    <button class="btn btn-primary" type="submit">Submit form</button>
  </div>
</form>

사스

변수

$form-feedback-margin-top:          $form-text-margin-top;
$form-feedback-font-size:           $form-text-font-size;
$form-feedback-font-style:          $form-text-font-style;
$form-feedback-valid-color:         $success;
$form-feedback-invalid-color:       $danger;

$form-feedback-icon-valid-color:    $form-feedback-valid-color;
$form-feedback-icon-valid:          url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><path fill='#{$form-feedback-icon-valid-color}' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/></svg>");
$form-feedback-icon-invalid-color:  $form-feedback-invalid-color;
$form-feedback-icon-invalid:        url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='#{$form-feedback-icon-invalid-color}'><circle cx='6' cy='6' r='4.5'/><path stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/><circle cx='6' cy='8.2' r='.6' fill='#{$form-feedback-icon-invalid-color}' stroke='none'/></svg>");

믹신

두 개의 믹스인이 루프 를 통해 함께 결합되어 양식 유효성 검사 피드백 스타일을 생성합니다.

@mixin form-validation-state-selector($state) {
  @if ($state == "valid" or $state == "invalid") {
    .was-validated #{if(&, "&", "")}:#{$state},
    #{if(&, "&", "")}.is-#{$state} {
      @content;
    }
  } @else {
    #{if(&, "&", "")}.is-#{$state} {
      @content;
    }
  }
}

@mixin form-validation-state(
  $state,
  $color,
  $icon,
  $tooltip-color: color-contrast($color),
  $tooltip-bg-color: rgba($color, $form-feedback-tooltip-opacity),
  $focus-box-shadow: 0 0 $input-btn-focus-blur $input-focus-width rgba($color, $input-btn-focus-color-opacity)
) {
  .#{$state}-feedback {
    display: none;
    width: 100%;
    margin-top: $form-feedback-margin-top;
    @include font-size($form-feedback-font-size);
    font-style: $form-feedback-font-style;
    color: $color;
  }

  .#{$state}-tooltip {
    position: absolute;
    top: 100%;
    z-index: 5;
    display: none;
    max-width: 100%; // Contain to parent when possible
    padding: $form-feedback-tooltip-padding-y $form-feedback-tooltip-padding-x;
    margin-top: .1rem;
    @include font-size($form-feedback-tooltip-font-size);
    line-height: $form-feedback-tooltip-line-height;
    color: $tooltip-color;
    background-color: $tooltip-bg-color;
    @include border-radius($form-feedback-tooltip-border-radius);
  }

  @include form-validation-state-selector($state) {
    ~ .#{$state}-feedback,
    ~ .#{$state}-tooltip {
      display: block;
    }
  }

  .form-control {
    @include form-validation-state-selector($state) {
      border-color: $color;

      @if $enable-validation-icons {
        padding-right: $input-height-inner;
        background-image: escape-svg($icon);
        background-repeat: no-repeat;
        background-position: right $input-height-inner-quarter center;
        background-size: $input-height-inner-half $input-height-inner-half;
      }

      &:focus {
        border-color: $color;
        box-shadow: $focus-box-shadow;
      }
    }
  }

  // stylelint-disable-next-line selector-no-qualifying-type
  textarea.form-control {
    @include form-validation-state-selector($state) {
      @if $enable-validation-icons {
        padding-right: $input-height-inner;
        background-position: top $input-height-inner-quarter right $input-height-inner-quarter;
      }
    }
  }

  .form-select {
    @include form-validation-state-selector($state) {
      border-color: $color;

      @if $enable-validation-icons {
        &:not([multiple]):not([size]),
        &:not([multiple])[size="1"] {
          padding-right: $form-select-feedback-icon-padding-end;
          background-image: escape-svg($form-select-indicator), escape-svg($icon);
          background-position: $form-select-bg-position, $form-select-feedback-icon-position;
          background-size: $form-select-bg-size, $form-select-feedback-icon-size;
        }
      }

      &:focus {
        border-color: $color;
        box-shadow: $focus-box-shadow;
      }
    }
  }

  .form-check-input {
    @include form-validation-state-selector($state) {
      border-color: $color;

      &:checked {
        background-color: $color;
      }

      &:focus {
        box-shadow: $focus-box-shadow;
      }

      ~ .form-check-label {
        color: $color;
      }
    }
  }
  .form-check-inline .form-check-input {
    ~ .#{$state}-feedback {
      margin-left: .5em;
    }
  }

  .input-group .form-control,
  .input-group .form-select {
    @include form-validation-state-selector($state) {
      @if $state == "valid" {
        z-index: 1;
      } @else if $state == "invalid" {
        z-index: 2;
      }
      &:focus {
        z-index: 3;
      }
    }
  }
}

지도

이것은 의 유효성 검사 Sass 맵입니다 _variables.scss. 이를 재정의하거나 확장하여 다른 상태나 추가 상태를 생성합니다.

$form-validation-states: (
  "valid": (
    "color": $form-feedback-valid-color,
    "icon": $form-feedback-icon-valid
  ),
  "invalid": (
    "color": $form-feedback-invalid-color,
    "icon": $form-feedback-icon-invalid
  )
);

의 맵 $form-validation-states에는 툴팁 및 포커스 스타일을 재정의하는 세 가지 선택적 매개변수가 포함될 수 있습니다.

고리

$form-validation-states검증 스타일을 생성하기 위해 맵 값 을 반복하는 데 사용됩니다 . 위의 Sass 맵에 대한 모든 수정 사항은 이 루프를 통해 컴파일된 CSS에 반영됩니다.

@each $state, $data in $form-validation-states {
  @include form-validation-state($state, $data...);
}

커스터마이징

$form-validation-states검증 상태는 지도 와 함께 Sass를 통해 사용자 정의할 수 있습니다 . 파일에 있는 _variables.scss이 Sass 맵은 기본 valid/ invalid검증 상태를 생성하는 방법입니다. 각 주의 색상, 아이콘, 도구 설명 색상 및 초점 그림자를 사용자 정의하기 위한 중첩 맵이 포함되어 있습니다. 브라우저에서 지원하는 다른 상태는 없지만 사용자 정의 스타일을 사용하는 상태에서는 더 복잡한 양식 피드백을 쉽게 추가할 수 있습니다.

mixin 을 수정하지 않고 값을 사용자 정의하는 것은 권장하지 않습니다$form-validation-statesform-validation-state .