🎨

フォームタグ外に送信ボタンを切り分け

2023/09/19に公開2

背景

一般的には formタグ内に<button type="submit"> があるのが普通です。
でもデザインやコンポーネントの切り分け的に、どうしてもフォームタグ外に送信ボタンをおかなくてはいけないケースもあるかと思います。

react-hook-formのissuesでも上がってました。
https://github.com/react-hook-form/react-hook-form/issues/566

Formタグ外に送信ボタン

<form id="applicationForm">
  {/* フォーム内容 */}
</form>
<button type="submit" form="applicationForm">送信</button>

ボタンがフォームタグ外にあるにも関わらずきちんと動きます。
formタグのidと、buttonタグのform属性の名称が同じになることで関連付け されます。

実装例

react-hook-formを使用して、formタグ内でなくモーダルコンポーネント内にボタンを置く

フォーム画像

フォームコンポーネント

function ApplicationForm({id, setButtonState, onSubmit}) {

 const { handleSubmit, formState } = useForm();
 const { isValid } = formState

 useEffect(() => {
   setButtonState(() => !isValid)
 }, [isValid])

 //...

 return (
  <form id={id} onSubmit={handleSubmit(onSubmit)}>
   {/* フォーム内容 */}
  </form>
 )
}

モーダルコンポーネント

function MyModal(() {

  /** ボタンの状態管理 */
 const [buttonState, setButtonState] = useState(true)
 
 const handleSubmitForm = (data) => {
    console.log(data);
 }

 //...

 return(
  <Modal>
   <ModalContent>
    <ApplicationForm
       id="appForm"  //関連付け
       setButtonState={setButtonState}
       onSubmit={handleSubmitForm} />
    <Button
       type="submit"
       form="appForm"  //関連付け
       isDisabled={buttonState}>
       編集
    </Button>
   </ModalContent>
  </Modal>
 )
}

フォームコンポーネントとモーダルコンポーネントで分けることでスッキリし、モーダルを汎用的に使用できます。
ボタンの活性状態も管理できます。

参考文献

How to submit the form outside the form
Submit button outside the form

Discussion

nap5nap5

formタグのidと、buttonタグのform属性の名称が同じになることで関連付け

便利ですよね。ぼくも少しチャレンジしてデモを作ってみました。

ボタンの活性状態も管理できます。

コンポーネントに切り出したときは、親コンポーネントをFormProviderで包み込み、子コンポーネント内でuseFormContext経由でサブスクするとフォームの状態を拾えます

https://codesandbox.io/p/devbox/back-demo-cl54qn?file=%2Fsrc%2FApp.tsx%3A1%2C1