フォーム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がすること
data-magic-formが付いたフォームのaction(https://form.magichtml.dev/f/SITE_ID/contact)から、公開中のフォーム定義を取得します。- HTMLの入力欄の名前と定義の項目を照合し、食い違いがあればブラウザのコンソールに警告を出します。フォームは無効にせず、判定はサーバーに任せます。
- 送信時に、サーバーと同じルールとメッセージで入力をチェックします。エラーがあれば送信を止め、項目ごとにメッセージを表示し、最初のエラー項目にフォーカスを移します。エラーを表示した項目は、入力のたびに再チェックします。
- ブラウザ標準の入力チェックの吹き出しは無効にします(フォームに
novalidateを設定します)。 - チェックを通ったら送信ボタンを無効にし、送信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件ずつアップロードします。
- 入力値をJSONで送信します。
- 受け付けられたら、フォームの「移動先」が設定されていればそのURLへ移動します(
/で始まるパスは現在のページを基準にします)。 - 移動先がなければフォームをリセットし、
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 に差し替えてください。