ドキュメントの目次
  1. はじめに
  2. HTMLフォームで送信する
  3. フォームSDK
  4. 項目と入力ルール
  5. メール通知と自動返信
  6. API

フォームSDK

フォームSDK(npm パッケージ @magichtml/form)は、Magic Form Cloud のフォームに送信前の入力チェックと送信の補助を加える JavaScript です。<script> タグで読み込み、<form> に data-magic-form を付けるだけで動きます。SDKがなくてもフォームは送信でき、最終的な判定は常にサーバーが行います。このページでは、読み込み方、属性、送信モード、window.MagicForm のAPI、サーバーとの違い、バージョンの方針を説明します。

読み込み

jsDelivr から、バージョンを固定したURLと integrity(SRIハッシュ)付きで読み込みます。

<script src="https://cdn.jsdelivr.net/npm/@magichtml/form@0.1.1/magic-form.js" integrity="sha384-jSxe35HuXAjr/zPizWoeOFtWrvkIShOoXAQc6OWUyXGDtZ6OIfCaepb97ddWluev" crossorigin="anonymous" defer></script>
  • ES モジュールではなく、通常の <script> として読み込みます。依存ライブラリやビルド作業は不要です。
  • defer を付けると、ページの読み込み後に動き始めます。
  • フォーム画面の「接続・公開履歴」にある「HTMLサンプル」には、このタグが固定バージョンと integrity 付きで入っています。

WordPressで読み込む

WordPress は、テーマで読み込むスクリプトに integrity と crossorigin を自動では付けません。テーマの functions.php で読み込み、script_loader_tag フィルターで属性を付けてください。

add_action('wp_enqueue_scripts', function () {
    if (is_page('contact')) {
        wp_enqueue_script('magic-form', 'https://cdn.jsdelivr.net/npm/@magichtml/form@0.1.1/magic-form.js', [], null, ['in_footer' => true, 'strategy' => 'defer']);
    }
});

add_filter('script_loader_tag', function ($tag, $handle) {
    if ($handle !== 'magic-form') {
        return $tag;
    }

    return str_replace(' src=', ' integrity="sha384-jSxe35HuXAjr/zPizWoeOFtWrvkIShOoXAQc6OWUyXGDtZ6OIfCaepb97ddWluev" crossorigin="anonymous" src=', $tag);
}, 10, 2);

contact は、フォームを置くページのスラッグです。フォームのHTMLは、テーマのテンプレートかブロックエディターの「カスタムHTML」ブロックに置きます。

SDKがすること

  1. data-magic-form が付いたフォームの action(https://form.magichtml.dev/f/SITE_ID/contact)から、公開中のフォーム定義を取得します。
  2. HTMLの入力欄の名前と定義の項目を照合し、食い違いがあればブラウザのコンソールに警告を出します。フォームは無効にせず、判定はサーバーに任せます。
  3. 送信時に、サーバーと同じルールとメッセージで入力をチェックします。エラーがあれば送信を止め、項目ごとにメッセージを表示し、最初のエラー項目にフォーカスを移します。エラーを表示した項目は、入力のたびに再チェックします。
  4. ブラウザ標準の入力チェックの吹き出しは無効にします(フォームに novalidate を設定します)。
  5. チェックを通ったら送信ボタンを無効にし、送信IDと公開版IDを付けて送信します。

基本のマークアップ

<form action="https://form.magichtml.dev/f/SITE_ID/contact" method="post" data-magic-form>
  <p data-magic-form-error></p>
  <label>お名前 <input name="name"></label>
  <p data-magic-error="name"></p>
  <label>メールアドレス <input type="email" name="email"></label>
  <p data-magic-error="email"></p>
  <label>お問い合わせ内容 <textarea name="message"></textarea></label>
  <p data-magic-error="message"></p>
  <input type="text" name="_hp" tabindex="-1" autocomplete="off" hidden>
  <button data-magic-submitting-text="送信中…">送信</button>
</form>
<div data-magic-success hidden></div>
<script src="https://cdn.jsdelivr.net/npm/@magichtml/form@0.1.1/magic-form.js" integrity="sha384-jSxe35HuXAjr/zPizWoeOFtWrvkIShOoXAQc6OWUyXGDtZ6OIfCaepb97ddWluev" crossorigin="anonymous" defer></script>

action は実際の送信先URLなので、SDKを読み込めなかった場合も同じHTMLのまま送信できます。

属性

属性 付ける場所 意味
data-magic-form <form> このフォームをSDKの対象にします。action から定義とJSON送信先のURLを求めます
data-magic-mode="native" <form> 既定。チェック後にブラウザが通常どおりPOSTします
data-magic-mode="fetch" <form> JSONで送信し、ページを移動せずに完了表示します
data-magic-error="キー" フォーム内の要素 その項目のエラーメッセージの表示先。なければ入力欄の後ろに自動で追加します
data-magic-form-error フォーム内の要素 項目に属さないメッセージ(定義にない項目、通信エラー、サーバーのエラー)の表示先。なければフォームの先頭に自動で追加します
data-magic-success ページ内の要素 fetch モードで完了メッセージを表示する場所
data-magic-submitting-text 送信ボタン 送信中にボタンに表示する文字
  • data-magic-error の要素を省略した場合、メッセージの要素は入力欄を囲む <fieldset>、<label>、入力欄自体の順に探した直後に追加されます。
  • エラーのある入力欄には aria-invalid="true" を設定し、aria-describedby でメッセージの要素と関連付けます。メッセージの要素には aria-live="polite" を設定します。

送信モード

native(既定)

チェックを通ると、フォームに _request_id(送信ID)と _version(公開版ID)の隠しフィールドを追加し、ブラウザが通常どおり送信します。その後の動作(完了ページや移動先への移動、エラーページ)は HTMLフォームで送信する と同じです。

  • ファイル項目がある場合は、<form> に enctype="multipart/form-data" が必要です。
  • エラーページから「戻る」で戻ったときは、送信ボタンが再び押せる状態に戻ります。

fetch

data-magic-mode="fetch" を付けると、ページを移動せずにJSONで送信します。

  1. ファイル項目のファイルを1件ずつアップロードします。
  2. 入力値をJSONで送信します。
  3. 受け付けられたら、フォームの「移動先」が設定されていればそのURLへ移動します(/ で始まるパスは現在のページを基準にします)。
  4. 移動先がなければフォームをリセットし、data-magic-success の要素に完了メッセージ(未設定なら「送信が完了しました。ありがとうございました。」)を表示します。要素の中身はこの文字で置き換えられます。

サーバーが返した項目のエラーは、送信前チェックと同じ場所に表示します。通信エラーなど項目に属さないエラーは data-magic-form-error に表示します。ファイルを1件ずつ送るため、1回の送信あたり22MBの制限を受けません(1ファイルあたりの上限は変わりません)。

送信IDと重複

  • SDKは入力内容ごとに送信ID(UUID)を作り、ブラウザのセッションストレージに保存します。保存するのは入力内容のハッシュとIDだけで、入力内容そのものは保存しません。ファイルは名前・サイズ・更新日時で区別します。
  • 同じブラウザのセッションで同じ内容を再送すると同じIDが使われ、サーバーは重複として扱います。2件目の受付もメールも作られず、完了として扱われます。
  • 入力を変えると新しいIDになります。
  • 送信中はボタンを無効にするため、ダブルクリックによる二重送信も防げます。

定義を読み込めない場合

次の場合、SDKはフォームに何もせず、フォームは通常のHTMLフォームとして送信されます(判定はサーバーが行います)。

  • フォーム定義の取得に失敗した(公開されていない、通信エラー、接続元が許可されていないなど)
  • action が Magic Form Cloud の送信先URL(/f/SITE_ID/キー の形式)ではない

いずれの場合もブラウザのコンソールに警告を出します。定義の取得は接続元の確認を受けるため、フォームを設置するページのオリジンをサイト設定に登録してください。

window.MagicForm

SDKを読み込むと window.MagicForm が使えます。ページ内の form[data-magic-form] は自動で対象になります。

名前 内容
VERSION SDKのバージョン文字列
MESSAGES 既定のエラーメッセージ(コードごとの日本語)
setMessages(overrides) コードごとにメッセージを置き換えます
validate(fields, input) 定義と入力値をチェックし、{values, violations} を返します
nativeValues(fields, entries) フォームの送信データを、サーバーのネイティブPOSTと同じ規則で値に変換します
endpoints(action) 送信先URLから、定義・JSON送信・アップロードのURLを求めます
enhance(form) フォームをSDKの対象にします
focusFirst(form, violations) エラーのある最初の入力欄(文書内の順)にフォーカスします

メッセージを変える

{label} は項目名に置き換わります。呼び出すたびに既定のメッセージからの置き換えになるため、変更するメッセージはまとめて1回で渡します。

<script>
  addEventListener('DOMContentLoaded', () => {
    MagicForm.setMessages({
      required: '{label}は必須です。',
      email: '{label}を正しい形式で入力してください。',
    });
  });
</script>

置き換わるのはSDKが送信前チェックで表示するメッセージだけです。サーバーのエラーページや、fetch モードでサーバーが返したメッセージは変わりません。コードの一覧は 項目と入力ルール を参照してください。

後から追加したフォームを対象にする

自動で対象になるのは、ページ読み込み時にあったフォームだけです。後からDOMに追加したフォームは enhance を呼びます。戻り値は Promise で、対象になれば true、通常のフォームのまま送信される場合は false になります。

const form = document.querySelector('#contact');
const enhanced = await MagicForm.enhance(form);

値をチェックする

const fields = [
  { key: 'email', label: 'メールアドレス', type: 'email', required: true },
];
const { values, violations } = MagicForm.validate(fields, { email: 'bad' });
// violations: [{ field: 'email', code: 'email', params: {}, message: 'メールアドレスのメール形式が不正です。' }]

fields には、フォーム定義APIが返す fields をそのまま渡せます。

フォームのデータを変換する

const values = MagicForm.nativeValues(fields, [...new FormData(form)]);

_ で始まる名前を除き、キー[] を一覧に、同意・はい/いいえを真偽値に変換し、空のファイル入力を無視します。

URLを求める

MagicForm.endpoints('https://form.magichtml.dev/f/SITE_ID/contact');
// { key: 'contact', schema: '…/resources/contact', submissions: '…/forms/contact/submissions', uploads: '…/forms/contact/uploads' }

SITE_ID は実際のサイトID(UUID)である必要があります。送信先URLの形式でなければ null を返します。

サーバーとの違い

SDKのチェックはサーバーと同じルールで行いますが、次の点は意図的に異なります。原則として、SDKはサーバーが拒否するものを通すことはあっても、サーバーが受け付けるものを拒否しないように作られています。

項目 SDK サーバー
メールアドレス @ の前後に空白と @ 以外の文字があり、ドメイン部に . を含む形式(緩め) より厳密な形式チェック
ファイル形式 拡張子から判定し、不明な場合はブラウザが報告する種類を使う ファイルの中身から判定
ファイルの重複 名前・サイズ・更新日時で判定 アップロードされたファイルのIDで判定
保存容量・有効期限など チェックしない チェックする

そのため、SDKのチェックを通った送信がサーバーで拒否されることがあります。native モードではエラーページ、fetch モードではフォーム内にメッセージが表示されます。

バージョンの方針

  • URLには正確なバージョンを指定し、integrity を付けて読み込んでください。
  • magic-form.js への変更はすべて新しいバージョンとして公開され、公開済みのファイルが後から変わることはありません。そのため、同じURLと integrity の組み合わせは使い続けられます。
  • 新しいバージョンを使う場合は、管理画面のHTMLサンプルに表示されるURLと integrity に差し替えてください。