Skip to content
This page has been auto-translated and may contain errors.View in English

폼 검증

docs.scrimba.com

은 사람들로부터 입력을 수집하며, 사람들은 필드를 비우거나, 이메일을 잘못 입력하거나, 숫자가 들어가야 하는 곳에 글자를 넣기도 합니다. 그런 데이터가 코드에 그대로 도달하는 것을 원하지 않을 것입니다. 제출되기 전에 브라우저는 많은 부분을 검사할 수 있지만, 각 필드가 무엇을 기대하는지 설명해야만 합니다. 그 설명은 HTML에 직접 작성되며, 이 장은 어떻게 작성하는지에 관한 것입니다.

필수 필드와 입력 타입

추가할 수 있는 가장 간단한 검사는 필드가 반드시 채워져야 한다고 말하는 것과 그곳에 어떤 종류의 값이 들어가야 하는지 말하는 것입니다.

입력에 required 단어를 추가하면 브라우저는 해당 필드에 무언가가 입력될 때까지 폼 제출을 거부합니다. 이를 작동시키기 위해 코드를 작성할 필요가 없습니다. 속성이 그 명령입니다.

html
<input type="text" name="full_name" required>

다른 절반은 type 속성입니다. 이것은 브라우저에 값이 어떤 형태여야 하는지 알려주며, 브라우저는 이를 검사합니다. type="email"을 사용하면 브라우저는 값이 이메일 주소처럼 보이도록 합니다. type="number"을 사용하면 숫자만 허용합니다. 날짜를 위한 타입, 웹 주소를 위한 타입 등이 있습니다.

의사 사무실의 양식을 생각해보세요. 일부 상자는 "반드시 작성"으로 표시되어 있고, 날짜 상자에는 이미 일, 월, 연도를 위한 작은 칸이 있습니다. 그 종이는 당신이 뭔가를 쓰기 전에 무엇이 어디에 들어가는지 알려주고 있습니다.

required는 **불린 속성**입니다. 속성의 존재만으로도 규칙이 작동하며, 값이 필요 없습니다. required로 표시된 컨트롤은 빈 상태에서 폼 제출을 차단합니다.

type 속성은 이중 역할을 합니다. 브라우저가 렌더링하는 컨트롤(날짜 선택기, 숫자 스핀너)을 선택하고 값에 대한 기본 제약을 설정합니다:

  • type="email"@와 도메인 형태의 끝부분이 필요합니다.
  • type="url"은 절대 웹 주소로 파싱되는 것이 필요합니다.
  • type="number"는 숫자 입력만 허용하며 min, max, step을 활성화합니다.
  • type="tel"은 값을 제약하지 않지만, 모바일에서 전화 키패드를 표시합니다.

다른 것들보다 먼저 구체적인 타입을 사용하세요. 최소한의 코드로 가장 많은 검사를 제공하며, 터치 기기에서 사람들이 얻는 화면 키보드도 개선됩니다.

requiredtype은 플랫폼이 **제약 검증**이라고 부르는 첫 두 가지 계층입니다. 이는 브라우저의 기본 제공 시스템으로 마크업에서 선언한 규칙에 대해 컨트롤의 값을 검사합니다. required는 "값 누락" 규칙을 설정합니다. type은 그 타입과 연결된 형식 규칙을 설정합니다.

type에 대한 두 가지 프로덕션 참고 사항이 있습니다. 첫째, type="email"은 전체 이메일 사양에 대해 검증하지 않습니다. 브라우저는 의도적으로 관대한 패턴을 사용합니다. (문자 실행, @, 그 다음 점으로 구분된 도메인) 더 엄격한 검사는 실제로 배달 가능한 주소를 거부할 것이기 때문입니다. 이를 주소가 실제로 존재한다는 증명이 아닌 형태 검사로 취급하세요. 둘째, 알 수 없거나 지원되지 않는 typetype="text"로 폴백되므로, 필드는 이전 브라우저에서 사용할 수 없게 되지 않으며, 추가 검사만 손실됩니다. 그 우아한 폴백이 호환성 표를 손에 들지 않고도 최신 타입을 채택할 수 있는 이유입니다.

타입은 또한 화면 키보드를 구동하며, 관련된 inputmode 속성(검증을 변경하지 않으면서 어떤 키보드 레이아웃을 표시할지에 대한 힌트)을 통해 그 키보드를 독립적으로 조정할 수 있습니다. 타입을 올바르게 하는 것은 검증만큼이나 접근성과 인체공학적 결정입니다.

다음은 두 속성을 모두 사용하는 작은 가입 폼입니다:

html
<form>
  <label>
    Email address
    <input type="email" name="email" required>
  </label>
  <label>
    Website
    <input type="url" name="website">
  </label>
  <button>Sign up</button>
</form>

이메일 필드는 반드시 채워져야 하며 이메일처럼 보여야 합니다. 웹사이트 필드는 선택사항이지만, 누군가 뭔가 입력하면 웹 주소처럼 보여야 합니다. 브라우저는 버튼을 누르는 순간 둘 다 검사합니다.

Juno필수 필드와 입력 타입 두 개의 작은 단어가 많은 작업을 합니다. 필드에 required를 넣으면 브라우저는 빈 필드를 통과시키지 않습니다. email 또는 number와 같은 type을 설정하면 값이 올바른 형태인지 검사합니다. 필드와 일치하는 타입을 선택하면 무료로 검사를 얻습니다.
Juno필수 필드와 입력 타입required는 불린 속성입니다: 있거나 없거나 하며, 값이 필요 없습니다. type은 컨트롤과 형식 규칙을 모두 선택하므로, type="email"@와 도메인을 원합니다. 항상 가장 구체적인 타입부터 시작하세요. 최소한의 마크업으로 최대의 검사를 제공하며, 모바일 키보드도 더 좋아집니다.
Juno필수 필드와 입력 타입 이것들은 제약 검증의 첫 두 계층이며, 브라우저의 기본 제공 규칙 검사기입니다. 기억할 가치가 있는 것: type="email"은 느슨한 형태 검사이며, 주소가 실제로 존재한다는 증명이 아니며, 지원되지 않는 타입은 깨지는 대신 조용히 text로 폴백됩니다. 타입 선택은 사람들이 얻는 화면 키보드를 설정하므로 접근성 결정이기도 합니다.

제약 속성

"채워짐"과 "올바른 타입"을 넘어서, 당신은 종종 제한을 원할 것입니다: 최소한 이 길이의 값, 그보다 크지 않은 숫자, 특정 형식의 코드입니다. 몇 가지 속성이 이를 다룹니다.

필드가 허용하는 것에 제한을 설정할 수 있습니다. 시작하기에 유용한 두 가지:

html
<input type="text" name="username" maxlength="20">
<input type="number" name="quantity" min="1" max="10">

maxlength="20"은 필드가 20자를 보유하면 멈춥니다. minmax는 허용되는 가장 작은 수와 가장 큰 수를 설정합니다. 브라우저는 사람들을 이러한 경계 내에 두므로 당신이 직접 검사할 필요가 없습니다.

제약 속성의 작은 세트가 있으며, 각각 하나의 규칙에 매핑됩니다:

  • minlength / maxlength는 텍스트 값이 가질 수 있는 최소와 최대 문자 수를 설정합니다.
  • min / max는 숫자와 날짜의 최저값과 최고값을 설정합니다.
  • step은 숫자의 허용된 증분을 설정하므로, step="5"는 0, 5, 10을 허용하고 3을 거부합니다.
  • pattern정규식(허용된 텍스트의 정확한 형태를 설명하는 간단한 표기법)을 보유하며, 값은 완전히 일치해야 합니다.
html
<input type="text" name="username" minlength="3" maxlength="20" required>
<input type="number" name="quantity" min="1" max="10" step="1">
<input type="text" name="pin" pattern="[0-9]{4}" title="네 자리">

patterntitle을 함께 사용하세요: 일부 브라우저는 오류 메시지에 텍스트를 표시하며, 이는 시각적 사용자들에게 필드가 무엇을 기대하는지 알려줍니다. CSS에서 :valid:invalid를 사용하여 컨트롤이 현재 제약을 통과하는지 여부에 따라 스타일을 지정할 수 있습니다.

각 제약 속성은 브라우저가 컨트롤에 대해 발생시킬 수 있는 하나의 플래그에 해당하며, 이는 JavaScript에서 검증 상태를 읽으면 중요합니다. min 위반은 "범위 미달", maxlength 초과는 "너무 김", pattern 불일치는 "패턴 불일치"를 발생시키며, 기타 등등입니다. 속성은 선언이고, 플래그는 결과가 보고되는 방식입니다.

사람들을 혼동시키는 두 가지 세부사항이 있습니다. pattern은 암시적으로 앵커되어 있습니다: 표현식은 전체 값과 일치해야 하며, 마치 시작부터 끝까지 포함하도록 래핑된 것처럼 작동하므로, pattern="[0-9]{4}"는 "내부의 어딘가에 4자리"가 아닌 정확히 4자리를 의미합니다. 그리고 step은 기본(있으면 min, 없으면 0)에서 부동소수점 산술을 사용하여 측정되므로, step="0.1"은 이진법이 소수를 나타내는 방식 때문에 통과할 것으로 예상되는 값을 거부할 수 있습니다. 정밀도가 중요할 때는 명시적 min을 기본으로 설정하세요.

:valid:invalid 의사-클래스(위치가 아닌 상태에 따라 요소와 일치하는 CSS 선택자)는 유용하지만 성글습니다: 빈 required 필드는 첫 페인트부터 :invalid와 일치하므로, 빨간색으로 스타일을 지정하면 사용자가 무언가를 입력하기 전에 오류로 인사합니다. 수정 방법은 :user-invalid이며, 이는 사람이 필드와 상호작용한 후에만 일치하므로, 피드백이 도착할 때 유용하기보다는 도착 시점에 나타납니다.

혼동을 덜어주는 규칙: a pattern must match the whole value, not only part of it.

html
<input
  type="text"
  name="product_code"
  pattern="[A-Z]{2}-[0-9]{3}"
  title="두 글자, 하이픈, 세 자리, 예: AB-123"
  required
>
Juno제약 속성 필드가 필수이고 타입이 지정되면, 제한을 추가할 수 있습니다. maxlength는 들어가는 문자 수를 제한하며, minmax는 숫자를 경계 짓습니다. 브라우저는 사람들을 자동으로 이러한 경계 안에 두므로, 직접 작성할 검사가 많이 줄어듭니다.
Juno제약 속성 세트는 작습니다: 텍스트는 minlength/maxlength, 숫자와 날짜는 min/max, 증분은 step, 정확한 형태는 pattern입니다. patterntitle을 지정하여 메시지가 의미 있게 만들어졌는지 확인하세요. 그리고 pattern은 전체 값과 일치하므로, [0-9]{4}는 내부의 어딘가의 4자리가 아닌 총 4자리입니다.
Juno제약 속성 각 속성은 나중에 읽을 수 있는 하나의 검증 플래그에 매핑되므로, 마크업과 보고가 일치합니다. 두 가지 주의점: pattern은 끝에서 끝까지 앵커되어 있으며, step은 기본값에서 부동소수점 수학을 사용하므로, 정밀도가 중요할 때 명시적 min을 설정하세요. :invalid가 아닌 :user-invalid로 스타일을 지정하세요. 아니면 누군가가 입력하기 전에 건드려지지 않은 필드를 빨간색으로 칠할 것입니다.

기본 검증 피드백

규칙을 선언하는 것은 이야기의 절반입니다. 다른 절반은 값이 하나를 깨뜨릴 때 사람이 보는 것입니다.

누군가 제출 버튼을 누르고 필드가 잘못되었을 때, 브라우저는 제출을 중지하고 문제가 있는 첫 번째 필드 옆에 작은 메시지를 표시한 다음 커서를 그곳으로 이동시킵니다. 이 메시지를 구축할 필요가 없습니다. 브라우저가 이를 작성하며, 방문자의 자신의 언어로, 자동으로 표시합니다.

따라서 비운 채로 둔 required 이메일 필드는 "이 필드를 작성하세요"와 같은 것을 생성하며, 고쳐질 때까지 폼은 전송되지 않습니다.

검증은 제출 시 실행됩니다. 브라우저는 컨트롤을 순서대로 탐색하여 첫 번째 유효하지 않은 것을 찾고, 포커스하며, 문제를 설명하는 작은 메시지 버블을 표시합니다. 모든 것이 통과하면 폼은 정상적으로 제출됩니다.

CSS를 통해 약간의 스타일 제어를 얻습니다. :required, :valid, :invalid, :in-range를 사용하여 필드를 시각적으로 표시할 수 있습니다. 쉽게 다시 스타일할 수 없는 것은 메시지 버블 자체입니다. 그 모양은 브라우저의 것이지, 당신의 것이 아닙니다. 또한 novalidate 속성으로 폼의 전체 시스템을 전환할 수 있으며, 이는 JavaScript에서 전적으로 검증하려고 할 때 유용합니다.

css
input:user-invalid {
  border-color: #c0392b;
}
input:user-valid {
  border-color: #2d7a3f;
}

기본 피드백은 편하고 거의 무료이며, 배송된 제품에서 이를 사용하기 전에 계획할 가치가 있는 제한 사항이 함께 옵니다.

메시지 버블은 일시적 요소입니다: 제출 시 나타나고, 다음 상호작용 시 사라지며, 선택하거나 스타일을 지정할 수 있는 문서의 일부가 아닙니다. 스크린 리더 지원은 브라우저마다 고르지 않으므로, 버블만으로는 볼 수 없는 사람에게 오류를 알리는 신뢰할 수 있는 방법이 아닙니다. 그 텍스트는 또한 페이지의 lang이 아닌 브라우저의 언어로 지역화되므로, 영어로 작성된 폼은 브라우저가 프랑스어로 설정된 방문자에게 프랑스어 오류 메시지를 표시할 수 있습니다. 이는 사용자에게 맞지만 개발자에게는 놀랍습니다.

제출하지 않고도 같은 흐름을 직접 트리거할 수 있습니다: reportValidity()는 검사를 실행하고 버블을 요청 시 표시합니다. 하지만 빠른 프로토타입을 넘어서는 모든 것에 대해, 접근 가능한 패턴은 기본 버블을 억제하고(novalidate) 페이지에 고유한 오류 텍스트를 렌더링하여, 필드와 연결되도록 하여, 보이고, 스타일을 지정할 수 있으며, 안정적으로 알려지도록 합니다. 다음 섹션은 어떻게 하는지를 다룹니다.

Juno기본 검증 피드백 이것이 모든 그 속성들의 보상입니다: 나쁜 필드로 제출하면 브라우저는 작은 메시지를 팝업하고, 필드를 가리키며, 전송을 거부합니다. 그 텍스트를 작성하지 않았습니다. 브라우저가 했으며, 방문자의 언어로 했습니다. 많은 폼들에 대해, 이것이 당신이 필요로 하는 모든 피드백입니다.
Juno기본 검증 피드백 검사는 제출 시 실행됩니다: 첫 번째 나쁜 필드가 포커스와 메시지 버블을 얻으며, 폼은 통과할 때까지 유지됩니다. :user-valid:user-invalid로 필드를 스타일할 수 있지만, 버블 자체는 브라우저의 디자인입니다. 계획이 JavaScript에서 처리하는 것일 때 novalidate로 전체를 전환하세요.
Juno기본 검증 피드백 버블은 일시적이고 스타일을 지정할 수 없으며, 그 스크린 리더 지원은 고르지 않으며, 그 텍스트는 페이지의 언어가 아닌 브라우저의 언어를 따릅니다. 프로토타입에는 좋지만, 프로덕션에는 약합니다. 접근성이 중요할 때, novalidate를 추가하고 페이지에 고유한 오류 텍스트를 렌더링하여 보이고, 스타일을 지정하며, 적절히 알려질 수 있게 합니다.

JavaScript가 여전히 필요한 경우

기본 검증은 한 필드를 고유한 규칙에 대해 검사합니다. 많은 실제 검사는 그 형태에 맞지 않으며, 그것이 JavaScript가 들어오는 지점입니다.

브라우저가 독립적으로 검사할 수 없는 것들이 있습니다. 두 비밀번호 필드가 서로 일치하는지 여부. 사용자명이 다른 누군가에게 이미 사용되고 있는지 여부. 할인 코드가 실제인지 여부. 이 중 어느 것도 한 필드의 형태에 관한 것이 아니므로, 속성이 없으며, JavaScript를 사용하여 검사를 합니다.

이것은 HTML의 결함이 아닙니다. 기본 제공 검사는 코드 없이 일반적인 경우를 처리하며, JavaScript는 나머지를 처리합니다.

간격은 하나 이상의 필드에 따라 달라지거나, 페이지가 아직 가지지 않은 정보에 따라 달라지는 모든 것입니다. 일반적인 예는 두 비밀번호가 일치하는지 확인하는 것입니다. JavaScript에서 비교하고 결과를 setCustomValidity로 기본 시스템에 피드백합니다. 이는 컨트롤에 대한 사용자 정의 오류 메시지를 설정합니다 (빈 문자열은 "이것은 유효함"을 의미합니다):

html
<input type="password" id="password" name="password" required>
<input type="password" id="confirm" name="confirm" required>

비교 자체는 <script>에서 실행됩니다:

js
const password = document.querySelector("#password")
const confirm = document.querySelector("#confirm")

confirm.addEventListener("input", () => {
  // 빈 문자열은 오류를 지우고 필드를 유효로 표시합니다
  const message = confirm.value === password.value ? "" : "비밀번호가 일치하지 않습니다"
  confirm.setCustomValidity(message)
})

필드는 이제 기본 검증에 다른 것처럼 참여하며, 제출을 차단하고 비밀번호가 다를 때 당신의 메시지를 표시합니다. 사용자명 가용성과 같은 서버가 필요한 검사는 같은 형태를 따르지만 네트워크 요청 후 메시지를 설정합니다.

JavaScript는 제약 검증 API(폼 컨트롤에서 브라우저가 검증을 읽고 설정하기 위해 노출하는 속성과 메서드의 세트)를 통해 기본 검증에 접근합니다. 가장 많이 사용하는 부분들:

  • setCustomValidity(message)는 컨트롤에 사용자 정의 오류 문자열을 설정합니다. 비어있지 않은 문자열은 그것을 유효하지 않음으로 표시하고 그것의 메시지가 됩니다. 빈 문자열은 사용자 정의 오류를 제거합니다.
  • validity는 읽기 전용 ValidityState 객체입니다: 가능한 각 실패마다 하나의 불린 (valueMissing, typeMismatch, patternMismatch, rangeOverflow, tooLong, customError, 기타 등등), 그리고 전체 결과에 대한 valid. 필드가 실패했는지만 알기 위해 읽으세요. 그것이 실패했는지만이 아닙니다.
  • checkValidity()는 아무것도 표시하지 않고 참 또는 거짓을 반환합니다. reportValidity()는 같은 것을 하고 기본 버블을 표시합니다.

접근 가능한 오류는, 색상 자체로는 결코 충분하지 않습니다: 빨간 테두리는 스크린 리더나 빨간색을 녹색과 구분할 수 없는 누군가에게 아무것도 말하지 않습니다. 오류 텍스트를 그 필드와 연결하여 보조 기술이 함께 읽도록 하세요. 입력에 aria-describedby를 오류 요소의 id로 설정하세요 (이것은 스크린 리더에 "이 텍스트를 필드의 설명으로 읽으세요"라고 말함), 필드가 실패하는 동안 aria-invalid="true"를 설정하세요 (이것은 필드를 오류 상태에 있다고 발표함):

html
<input
  type="text"
  id="username"
  name="username"
  aria-describedby="username-error"
  aria-invalid="true"
  required
>
<p id="username-error" role="alert">그 사용자명은 이미 취해졌습니다.</p>

role="alert"는 스크린 리더에 메시지가 나타나자마자 발표하도록 만듭니다. Accessibility 장은 컨트롤을 그들의 설명과 연결하는 것에 대해 더 깊이 들어갑니다.

이는 트레이드오프를 남깁니다. 기본 검증은 코드가 적으며, 플랫폼과 일치하고, 스크립트가 로드되기 전에 작동하지만, 그 피드백은 스타일을 지정하고 알리기 어렵습니다. 사용자 정의 검증은 더 많은 코드와 더 많은 책임이지만, 단어, 타이밍, 접근성에 대한 완전한 제어를 제공합니다. 대부분의 프로덕션 폼은 둘 다를 사용합니다: 기본선으로서의 기본 속성, 검사와 메시징 속성이 도달할 수 없는 것들에 대해 계층화된 JavaScript입니다.

당신이 무엇을 선택하든, 하나의 규칙은 구부러지지 않습니다. 클라이언트 검증은 편의입니다. 절대 보장이 아닙니다. 이 장에서 설명된 모든 것은 방문자의 브라우저에서 실행되며, 누구든 그것을 끄거나, 페이지를 편집하거나, 폼을 전혀 건드리지 않고 서버에 요청을 직접 보낼 수 있습니다. 서버는 브라우저 검사가 일어났다는 것처럼 받은 모든 값을 재검증해야 합니다. 브라우저의 검사를 왕복을 절약하는 빠르고 친절한 첫 번째 검사로 취급하고, 서버를 실제로 데이터를 보호하는 검사로 취급하세요.

JunoJavaScript가 여전히 필요한 경우 기본 제공 검사는 한 번에 한 필드를 다루므로, "이 두 비밀번호가 일치하는가"와 같이 필드를 비교하거나, "이 사용자명은 무료인가"와 같이 서버와 검사하는 모든 것은 JavaScript가 필요합니다. 이는 정상입니다. HTML은 일상적인 경우를 무료로 처리하고, JavaScript는 그것이 스스로 볼 수 없는 것들을 처리합니다.
JunoJavaScript가 여전히 필요한 경우 검사가 두 필드에 걸쳐 있거나 서버가 필요할 때, JavaScript에서 계산하고 setCustomValidity로 결과를 반환하세요: 필드를 실패하는 메시지 문자열, 그것을 지우는 빈 문자열입니다. 필드는 그러면 다른 것처럼 기본 검증에 참여합니다. 비밀번호 일치와 사용자명 가용성이 고전적인 두 가지입니다.
JunoJavaScript가 여전히 필요한 경우 제약 검증 API는 당신의 훅입니다: 메시지를 설정하는 setCustomValidity, 필드가 실패한 이유를 읽는 validity, 검사를 실행하는 checkValidityreportValidity. 접근 가능한 오류는, aria-describedbyaria-invalid로 텍스트를 필드에 묶으세요. 색상만 해서는 안 됩니다. 그리고 선택사항이 아닌 것: 여기서의 모든 검사는 브라우저에서 실행되므로, 서버는 모든 것을 재검증해야 합니다.