접근 가능한 폼 오류 복구 설계: 식별·포커스·재검증
폼 제출이 실패했을 때 모든 사용자가 오류를 찾고 고친 뒤 다시 제출할 수 있도록 필드 식별자, 포커스, 서버 검증, 네트워크 실패를 한 흐름으로 설계하는 방법을 정리합니다.
접근 가능한 폼 오류 처리는 빨간 테두리를 추가하는 일이 아니라, 사용자가 무엇을 고쳐야 하는지 발견하고 다시 제출할 수 있게 만드는 흐름입니다. 서버와 브라우저가 같은 필드 식별자를 사용하고, 오류 요약에서 해당 입력으로 이동하며, 오류가 사라졌을 때 상태를 지우는 것이 핵심입니다.
WCAG 2.2의 오류 식별과 오류 제안 기준은 입력 오류를텍스트로 식별하고 가능한 수정 방법을 제시하도록 요구합니다. 아래 절차는 그 기준을 실제 폼 상태와 검증 응답에 연결합니다.

1. 오류를 한 가지 상태 모델로 정의하기
먼저 필드 이름, 오류 코드, 사용자 메시지, 포커스 대상, 재검증 시점을 하나의 상태로 묶습니다. 브라우저 기본 검증은 즉시 피드백을 줄 수 있지만 서버 규칙을 대신하지 않으므로, 서버 응답도 같은 필드 키를 반환해야 합니다.
오류 요약은 첫 번째 오류 필드의 id를 가리키고, 각 입력은 label과 연결된 id를 가져야 합니다. 입력 옆 설명에는 aria-describedby를 연결하고, 오류가 생기면 aria-invalid="true"를 설정합니다. 오류가 수정되면 이전 메시지와 invalid 상태를 함께 제거합니다.
2. 제출 전후의 순서를 고정하기
사용자가 제출 버튼을 누르면 먼저 클라이언트의 형식 검사를 실행하고, 실패하면 오류 요약을 폼 상단에 만들고 첫 오류 입력으로 포커스를 이동합니다. 서버 검증이 필요한 경우 버튼을 잠그되, 네트워크 실패를 필드 오류로 오인하지 않고 전역 상태로 분리합니다.
입력값을 정규화하고 필드별 규칙을 실행한다.
오류를 `{field, code, message}` 배열로 정렬해 요약과 필드 옆에 동시에 표시한다.
첫 오류 링크를 활성화하고 해당 입력에 포커스를 준다.
수정된 필드만 재검증하고 통과한 오류를 즉시 제거한다.
성공 응답에서는 요약·aria-invalid·오류 설명을 모두 정리하고 완료 메시지를 알린다.
오류 요약의 링크는 단순히 스크롤하는 대신 실제 입력 요소로 포커스를 보내야 합니다. 동적으로 렌더링되는 오류는 role="alert" 또는 적절한 라이브 영역으로 알리되, 모든 키 입력마다 문장을 읽어 방해하지 않도록 제출 결과와 상태 변화에 한정합니다.
3. 예시: 주소 폼의 서버 오류 복구
예시는 배송 주소 폼입니다. 입력은 `{postalCode: "123", city: ""}`이고, 결정은 우편번호 형식과 도시 필수 여부를 서버에서 재검증하는 것입니다. 중간 산출물은 다음 오류 배열이며, 기대 결과는 요약의 두 링크가 각각 postal-code와 city 입력으로 이동하는 것입니다.
[{"field":"postalCode","code":"format","message":"우편번호 5자리를 입력하세요."},{"field":"city","code":"required","message":"시/군/구를 입력하세요."}]
사용자가 우편번호를 수정하면 해당 항목만 재검증해 요약에서 제거합니다. 도시 입력까지 통과하면 서버에 다시 제출하고, 성공 시 포커스를 주문 확인 제목으로 옮겨 완료 상태를 알립니다. 이 과정에서 다른 필드의 값과 오류는 불필요하게 초기화하지 않습니다.
4. 실패 경로와 경계 조건
실패 경로는 네트워크 타임아웃을 postalCode 오류로 표시하는 경우입니다. 사용자는 올바른 값을 다시 입력해도 같은 메시지를 보게 되므로, 네트워크 문제는 폼 상단의 재시도 가능한 전역 메시지로 분리하고 입력값을 보존해야 합니다.
또 다른 경계는 자동 포커스가 모달이나 가상 키보드에 가려지는 모바일 화면입니다. 이때는 요약 링크를 먼저 노출하고, 포커스 이동 후 입력 위치가 보이도록 스크롤하되 사용자가 읽던 위치를 무조건 재설정하지 않습니다. 오류가 0개라는 응답도 성공으로 간주하기 전에 HTTP 상태와 응답 구조를 확인합니다.
5. 완료 조건과 운영 점검
완료 조건은 키보드만으로 제출→요약 링크→첫 오류 입력→수정→재제출이 가능하고, 스크린리더가 필드명·오류·성공 메시지를 한 번씩 이해할 수 있는 상태입니다. 테스트 기록에는 오류 배열, 포커스 대상 id, 수정 후 제거된 코드, 네트워크 실패 시 보존된 입력값을 남깁니다.
모든 입력에 고유 id와 연결된 label이 있는가
오류 요약 링크가 실제 입력으로 포커스를 보내는가
aria-invalid와 aria-describedby가 오류 생명주기와 함께 바뀌는가
필드 오류와 전역 네트워크 오류가 구분되는가
성공·실패 상태에서 사용자가 재시도하거나 다음 단계로 이동할 수 있는가
이 기록이 통과하면 폼 오류 복구를 완료한 것입니다. 반대로 메시지만 추가하고 포커스·식별자·재검증을 확인하지 않았다면 시각적 개선에 그친 것이므로 배포 전에 보류합니다. 운영 중에는 실제 키보드 순서와 확대 배율, 다국어 메시지 길이까지 같은 테스트 기록에 포함해 회귀를 빠르게 찾습니다. 오류 문구를 바꿀 때도 코드와 필드 연결은 유지해야 합니다.