본문으로 건너뛰기
개발 머꼬
개발 노트HTML
hohyeon.dev24

모달 밖으로 옮긴 저장 버튼이 폼을 제출하지 못한 이유

  • #Engineering Note
  • #HTML

문제 발생

모달의 푸터를 고정하려고 저장 버튼을 <form> 바깥으로 옮겼더니 아무 일도 일어나지 않았습니다.

<div class="modal-body">
  <form id="profile" action="/profile" method="post">
    <input name="nickname" />
  </form>
</div>
<div class="modal-footer">
  <button type="submit">저장</button>   <!-- 어떤 폼도 제출하지 못함 -->
</div>

표 안의 행마다 삭제 폼을 넣으려던 화면에서도 같은 문제가 있었습니다. <table> 안에는 <form>을 원하는 위치에 넣기 어렵습니다.

원인 분석

버튼은 자기를 감싼 폼을 제출합니다. MDN 설명대로 form 속성이 없으면 컨트롤은 가장 가까운 조상 폼과 연결되고, 조상 중에 폼이 없으면 어디에도 소속되지 않습니다. 그래서 마크업 위치를 바꾸는 순간 조용히 동작이 사라집니다.

해결책은 이미 HTML에 있습니다. MDN은 form 속성을 이렇게 설명합니다 — 이 입력이 연결될 <form> 요소(폼 소유자)를 지정하는 문자열이며, 값이 있다면 같은 문서 안 <form> 요소의 id와 일치해야 합니다. 그리고 목적을 한 문장으로 정리합니다 — form 속성은 입력을 문서의 어디에나 두면서도 다른 곳의 폼에 포함시킬 수 있게 해줍니다. 다만 하나의 입력은 하나의 폼에만 연결될 수 있습니다.

해결 방안

  1. 버튼과 입력에 form을 붙입니다. JS 없이 그대로 동작합니다.
<div class="modal-footer">
  <button type="submit" form="profile">저장</button>
</div>
  1. 표 안의 행 단위 액션에도 같은 방식을 씁니다. <form>을 표 바깥에 두고 행의 버튼만 연결하면 마크업이 유효해집니다.

  2. 버튼마다 다른 동작이 필요하면 formaction을 씁니다. MDN 설명대로 제출 버튼의 formaction/formmethod/formenctype/formtarget은 각각 폼의 action/method/enctype/target덮어씁니다.

<form id="post" action="/posts/1" method="post">
  <button type="submit">저장</button>
  <button type="submit" formaction="/posts/1/preview">미리보기</button>
</form>
  1. "취소"에는 formnovalidate를 검토합니다. 같은 폼의 다른 제출 버튼이 검증에 막혀 동작하지 않는 상황을 피할 수 있습니다.

  2. JS로 대체하지 않습니다. onClick={() => form.submit()} 방식은 브라우저의 기본 검증을 건너뛰고, JS가 로드되기 전에는 동작하지 않습니다. 표준 속성으로 되는 일은 표준으로 둡니다.

  3. id가 문서 안에서 유일한지 확인합니다. 목록 화면에서 폼 id가 중복되면 첫 번째 것만 연결되어 두 번째 행부터 조용히 실패합니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.