Astroなどの静的サイトジェネレーターでWebサイトを制作するとき、問い合わせフォームの実装方法に悩んだことはありませんか?
静的サイトでは、HTMLやCSSだけでフォームの見た目を作ることはできても、入力された内容をメールで送信するには、別途送信処理を用意する必要があります。
そんなときに便利なのが、外部フォームサービスの「SSGform」です。
SSGformは、フォームのHTMLを自分で作成し、送信処理を外部サービスに任せられる仕組みです。静的サイトジェネレーターはもちろん、純粋なHTMLサイトやWordPressでも利用できます。
ただし、すべての案件でSSGformが最適というわけではありません。
この記事では、SSGformの特徴やほかのフォームサービスとの違いを整理した上で、実際に問い合わせフォームを実装してみます。
HTMLによるフォームの作成から、JavaScriptを使った入力チェック、送信後のサンクスページへの遷移まで、基本的な実装方法を紹介します。
SSGformとは?
SSGformは、Webサイトに問い合わせフォームを設置するための外部フォームサービスです。
サイト側でフォームのHTMLを作成し、SSGformが発行する専用URLに入力内容を送信することで、通知メールを受け取ることができます。
フォームのデザインや入力項目は自分で設計できるため、デザインカンプに合わせた問い合わせフォームを実装できます。

SSGform公式サイト
https://ssgform.com/
静的サイトジェネレーター以外でも使える
SSGformという名称から、AstroやHugoなどの静的サイトジェネレーター専用のサービスという印象を受けるかもしれません。
しかし、実際には純粋なHTMLサイトやWordPressでも利用できます。
基本的には、HTMLのform要素を設置できる環境であれば、SSGformを送信先として利用することが可能です。
SSGformは、静的サイトジェネレーターを利用している人だけでなく、HTML・CSS・JavaScriptを使ってWebサイトを制作している人にとっても、採用を検討する価値のあるサービスです。
フォームの送信処理を外部に任せられる
通常、問い合わせフォームを自作する場合、入力内容を受け取り、メールを送信するためのサーバー側の処理が必要です。
SSGformを利用すれば、この部分を外部サービスに任せることができます。
サイト側ではフォームのHTMLやデザイン、必要に応じた入力チェックなどを実装すればよく、メール送信の仕組みを一から構築する必要はありません。

SSGformのメリットとデメリット
SSGformを導入する前に、メリットとデメリットを整理しておきましょう。
メリット① フォームのデザインや入力項目を自由に設計できる
SSGformでは、フォームのHTMLを自分で作成します。
入力項目の配置やデザインを自由に調整できるため、サイト全体のデザインに合わせたフォームを実装できます。
JavaScriptによる入力チェックやエラーメッセージの表示なども、自分で設計できます。
メリット② サーバー側の送信処理を自作する必要がない
フォームの送信処理をSSGformに任せられるため、PHPなどを使ってメール送信機能を自作する必要がありません。
Astroなどで静的サイトを制作する場合にも、問い合わせフォームのためだけにサーバー側の処理を用意する必要がなくなります。
デメリット① フォームの実装にはHTMLなどの知識が必要
SSGformを利用しても、フォームのHTMLやCSSが自動的に生成されるわけではありません。
フォームの構造やデザイン、入力チェックなどは、基本的に自分で実装する必要があります。
そのため、HTMLやCSSの知識がない人が手軽にフォームを設置したい場合には、Googleフォームやformrunなどの方が適していることもあります。
また、WordPressであれば、Snow Monkey Formsなどのプラグインを利用した方が、少ない実装工数でフォームを設置できる場合もあるでしょう。
デメリット② 問い合わせの管理には工夫が必要
SSGformでは、送信された内容をメールで受け取ることができます。
一方、Googleフォームのように回答をGoogleスプレッドシートへ自動集計したり、formrunのように問い合わせの対応状況をカンバン形式で管理したりする機能は、SSGform単体では提供されていません。
問い合わせの件数が多い場合や、複数人で対応状況を共有する必要がある場合には、受信後の管理方法も考えておく必要があります。
なお、外部ツールと組み合わせれば、問い合わせの集計や管理を自動化することも可能です。この方法については、別の記事で紹介する予定です。
※補足:料金プランについて
SSGformには無料プランが用意されており、2026年9月時点では月間100件までのフォーム送信に対応しています。実案件への導入時には、想定送信件数や必要な機能、最新の利用条件を確認してください。
SSGform公式サイト:料金プラン
https://ssgform.com/plans
フォームサービスは案件の要件に合わせて選ぶ
問い合わせフォームの実装方法には、SSGform以外にもさまざまな選択肢があります。
例えば、フォームを手軽に作成したい場合にはGoogleフォーム、問い合わせの対応状況をチームで共有したい場合にはformrunなどが候補になります。
WordPressであれば、フォーム用のプラグインを利用する方法もあります。
重要なのは、フォームの実装方法だけでなく、クライアントがどのように問い合わせを受け取り、管理するのかまで考えることです。
また、問い合わせフォームが必要だからといって、サイト全体をWordPressで構築する必要はありません。
静的HTMLサイトやAstroでも、外部フォームサービスを利用すれば問い合わせフォームを設置できます。
サイトの構築方式は、コンテンツの更新方法や必要な機能、運用体制などを総合的に考えて選択したいところです。
次のセクションからは、HTMLやCSSでフォームを自由に設計しながら、送信処理を外部サービスに任せたいケースを想定し、SSGformを使って実装する方法を紹介します。
SSGformを使って問い合わせフォームを実装する
ここからは、実際にSSGformを使って問い合わせフォームを作成してみます。
今回は、HTML・CSS・JavaScriptを使ったシンプルなフォームを実装します。
AstroやWordPressを利用している場合も、基本的な考え方は同じです。

【STEP 1】SSGformのアカウントを作成する
まず、SSGformの公式サイトにアクセスし、アカウントを作成します。
アカウント作成後、管理画面から新しいフォームを作成すると、専用の送信先URLが発行されます。このURLを、後ほどHTMLのform要素に設定します。

【STEP 2】HTMLでフォームを作成する
続いて、HTMLで問い合わせフォームを作成します。
ここでは、氏名、メールアドレス、お問い合わせ内容、プライバシーポリシーへの同意を入力項目として用意します。
SSGformでは、フォームの送信先URLに入力内容をPOST送信します。
また、送信する入力項目にはname属性が必要です。
この部分を押さえておけば、通常のHTMLフォームとほぼ同じ感覚で実装できます。
特に、以下の点に留意します。
form要素のactionにSSGformの送信先URLを指定する。method="post"を指定する。- 各入力項目に
name属性を設定する。 labelと入力項目を関連付ける。required属性やtype="email"を設定する。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>お問い合わせ | サンプルサイト</title>
<meta name="description" content="サンプルサイトへのお問い合わせはこちらから。">
<link rel="stylesheet" href="./css/style.css">
<script src="./js/validation.js" defer></script>
</head>
<body>
<header class="l-header">
<div class="l-container">
<a href="/">サンプルサイト</a>
</div>
</header>
<main id="main" class="l-main">
<div class="l-container">
<h1>お問い合わせ</h1>
<p class="c-lead">
以下のフォームに必要事項をご入力の上、
送信してください。
</p>
<p class="c-form__note">
<span class="c-required">必須</span>
は入力必須項目です。
</p>
<form
id="contact-form"
class="c-form"
action="https://ssgform.com/s/XXXXXXXXXXXX"
method="post"
novalidate
>
<!-- 入力エラーの概要 -->
<div
id="form-error-summary"
class="c-form__summary"
role="alert"
tabindex="-1"
hidden
></div>
<!-- お名前 -->
<div class="c-form__field">
<label for="name" class="c-form__label">
お名前
<span class="c-required">必須</span>
</label>
<input
type="text"
id="name"
name="お名前"
class="c-form__input"
autocomplete="name"
required
aria-describedby="name-error"
>
<p
id="name-error"
class="c-form__error"
hidden
></p>
</div>
<!-- メールアドレス -->
<div class="c-form__field">
<label for="email" class="c-form__label">
メールアドレス
<span class="c-required">必須</span>
</label>
<input
type="email"
id="email"
name="メールアドレス"
class="c-form__input"
autocomplete="email"
inputmode="email"
required
aria-describedby="email-error"
>
<p
id="email-error"
class="c-form__error"
hidden
></p>
</div>
<!-- お問い合わせ内容 -->
<div class="c-form__field">
<label for="message" class="c-form__label">
お問い合わせ内容
<span class="c-required">必須</span>
</label>
<textarea
id="message"
name="お問い合わせ内容"
class="c-form__textarea"
rows="6"
required
aria-describedby="message-error"
></textarea>
<p
id="message-error"
class="c-form__error"
hidden
></p>
</div>
<!-- プライバシーポリシー -->
<div class="c-form__field">
<p id="privacy-description">
<a href="/privacy-policy/" target="_blank" rel="noopener">
プライバシーポリシー
<span class="c-visually-hidden">(新しいタブで開きます)</span>
</a>
をご確認の上、同意してください。
</p>
<div class="c-form__checkbox">
<input
type="checkbox"
id="privacy"
name="プライバシーポリシー"
value="同意する"
required
aria-describedby="privacy-description privacy-error"
>
<label for="privacy">
プライバシーポリシーに同意する
<span class="c-required">必須</span>
</label>
</div>
<p
id="privacy-error"
class="c-form__error"
hidden
></p>
</div>
<div class="c-form__actions">
<button type="submit" class="c-form__button">
送信する
</button>
</div>
</form>
</div>
</main>
<footer class="l-footer">
<div class="l-container">
<small>© サンプルサイト</small>
</div>
</footer>
</body>
</html>
ポイントはここです!form 要素の action 属性の値に、管理画面で取得した「送信先URL」を貼り付けます。
<form
id="contact-form"
class="c-form"
action="https://ssgform.com/s/XXXXXXXXXXXX"
method="post"
novalidate
>
【STEP 3】CSSでフォームのスタイリングを整える
フォームのHTMLを作成したら、CSSでデザインを調整します。
今回は、入力欄の余白やボーダー、フォーカス時の表示などを整え、シンプルな問い合わせフォームに仕上げます。
特に、以下の点に留意します。
- フォーカス時の視認性の確保
- エラーメッセージの表示
:root {
color-scheme: light;
font-family: system-ui, sans-serif;
line-height: 1.7;
color: #222;
background: #fff;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}
a {
color: #0759a3;
text-underline-offset: 0.2em;
}
a:hover {
text-decoration-thickness: 2px;
}
:focus-visible {
outline: 3px solid #0759a3;
outline-offset: 3px;
}
[hidden] {
display: none !important;
}
/* Layout */
.l-container {
width: min(100% - 32px, 720px);
margin-inline: auto;
}
.l-header,
.l-footer {
padding-block: 24px;
background: #f5f5f5;
}
.l-main {
padding-block: 48px 80px;
}
h1 {
margin: 0 0 24px;
font-size: clamp(1.75rem, 4vw, 2.25rem);
line-height: 1.4;
}
.c-lead {
margin-bottom: 32px;
}
/* Form */
.c-form__note {
margin-bottom: 24px;
font-size: 0.875rem;
}
.c-form__field {
margin-bottom: 32px;
}
.c-form__label {
display: block;
margin-bottom: 8px;
font-weight: 700;
}
.c-required {
display: inline-block;
margin-left: 8px;
padding: 2px 6px;
border-radius: 3px;
background: #9b1c1c;
color: #fff;
font-size: 0.75rem;
font-weight: 700;
line-height: 1.5;
}
.c-form__input,
.c-form__textarea {
display: block;
width: 100%;
padding: 12px;
border: 1px solid #666;
border-radius: 4px;
background: #fff;
color: #222;
font: inherit;
}
.c-form__textarea {
min-height: 160px;
resize: vertical;
}
.c-form__input:focus,
.c-form__textarea:focus {
border-color: #0759a3;
}
.c-form__input[aria-invalid="true"],
.c-form__textarea[aria-invalid="true"] {
border: 2px solid #9b1c1c;
}
.c-form__error {
margin: 8px 0 0;
color: #9b1c1c;
font-size: 0.875rem;
font-weight: 700;
}
.c-form__summary {
margin-bottom: 32px;
padding: 16px;
border: 2px solid #9b1c1c;
border-radius: 4px;
background: #fff5f5;
}
.c-form__summary:focus {
outline: 3px solid #0759a3;
outline-offset: 3px;
}
.c-form__summary p {
margin: 0;
font-weight: 700;
}
.c-form__summary ul {
margin: 8px 0 0;
padding-left: 24px;
}
.c-form__checkbox {
display: flex;
align-items: flex-start;
gap: 12px;
margin-top: 16px;
}
.c-form__checkbox input {
flex-shrink: 0;
width: 20px;
height: 20px;
margin: 4px 0 0;
accent-color: #0759a3;
}
.c-form__checkbox label {
cursor: pointer;
}
.c-form__checkbox input[aria-invalid="true"] {
outline: 2px solid #9b1c1c;
outline-offset: 3px;
}
.c-form__actions {
margin-top: 40px;
text-align: center;
}
.c-form__button {
display: inline-block;
min-width: 200px;
min-height: 48px;
padding: 12px 32px;
border: 2px solid #0759a3;
border-radius: 4px;
background: #0759a3;
color: #fff;
font: inherit;
font-weight: 700;
cursor: pointer;
}
.c-form__button:hover {
background: #03447f;
}
.c-form__button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
/* Screen reader only */
.c-visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
@media (max-width: 600px) {
.l-main {
padding-block: 32px 64px;
}
.c-form__button {
width: 100%;
}
}
フォームは見た目だけでなく、入力しやすさも重要です。
入力欄とラベルの対応関係や、キーボード操作時のフォーカス表示などにも配慮しておきましょう。
【STEP 4】JavaScriptでバリデーションを実装する
ここまでで、フォームの見た目は完成しました。
続いて、JavaScriptで入力内容をチェックする処理を追加します。
今回実装するのは、次のような基本的なバリデーションです。
- 必須項目が入力されているか確認する。
- メールアドレスの形式を確認する。
- プライバシーポリシーへの同意を確認する。
- 入力エラーがある場合は、該当する項目の近くにエラーメッセージを表示する。
- エラーがなければ、フォームを送信する。
HTMLのrequired属性やtype="email"でも基本的な入力チェックはできますが、JavaScriptを使うことで、エラーメッセージの表示方法などを調整できます。
今回は、ブラウザ標準の制約検証APIも活用しながら、必要な部分をJavaScriptで補う形にします。
なお、ブラウザ側のバリデーションは、利用者の入力ミスを防ぐための仕組みです。
JavaScriptを無効化したり、フォームを経由せずにデータを送信したりすることも可能なため、不正な送信を防ぐセキュリティ対策とは区別して考える必要があります。
(() => {
const form = document.querySelector("#contact-form");
if (!form) return;
const summary = document.querySelector(
"#form-error-summary"
);
const fields = [
{
input: form.querySelector("#name"),
label: "お名前",
error: form.querySelector("#name-error"),
},
{
input: form.querySelector("#email"),
label: "メールアドレス",
error: form.querySelector("#email-error"),
},
{
input: form.querySelector("#message"),
label: "お問い合わせ内容",
error: form.querySelector("#message-error"),
},
{
input: form.querySelector("#privacy"),
label: "プライバシーポリシーへの同意",
error: form.querySelector("#privacy-error"),
},
];
// 入力内容に応じたエラーメッセージを取得
function getErrorMessage(input) {
const validity = input.validity;
if (validity.valueMissing) {
if (input.type === "checkbox") {
return "同意が必要です。";
}
return "入力してください。";
}
if (validity.typeMismatch) {
return "メールアドレスの形式で入力してください。";
}
return "";
}
// 個別の入力項目を検証
function validateField(field) {
const { input, error } = field;
const message = getErrorMessage(input);
error.textContent = message;
error.hidden = !message;
if (message) {
input.setAttribute("aria-invalid", "true");
} else {
input.removeAttribute("aria-invalid");
}
return !message;
}
// エラー概要を非表示にする
function clearSummary() {
summary.replaceChildren();
summary.hidden = true;
}
// エラー概要を表示
function showSummary(invalidFields) {
const heading = document.createElement("p");
heading.textContent =
"入力内容に不備があります。以下の項目をご確認ください。";
const list = document.createElement("ul");
invalidFields.forEach((field) => {
const item = document.createElement("li");
const link = document.createElement("a");
link.href = `#${field.input.id}`;
link.textContent =
`${field.label}:${getErrorMessage(field.input)}`;
// リンク先の入力項目にフォーカスを移動
link.addEventListener("click", (event) => {
event.preventDefault();
field.input.focus();
});
item.append(link);
list.append(item);
});
summary.replaceChildren(heading, list);
summary.hidden = false;
// スクリーンリーダーにもエラー概要を通知
summary.focus();
}
// 入力後の再検証
fields.forEach((field) => {
const eventName =
field.input.type === "checkbox"
? "change"
: "input";
field.input.addEventListener(eventName, () => {
// エラー表示後のみ再検証
if (
field.input.getAttribute("aria-invalid") === "true"
) {
validateField(field);
}
});
// フォーカスが外れたときにも検証
field.input.addEventListener("blur", () => {
validateField(field);
});
});
// フォーム送信時の検証
form.addEventListener("submit", (event) => {
clearSummary();
const invalidFields = fields.filter(
(field) => !validateField(field)
);
if (invalidFields.length > 0) {
event.preventDefault();
showSummary(invalidFields);
return;
}
// 正常な場合はブラウザ標準のフォーム送信を実行
});
})();
【STEP 5】送信後のサンクスページを設定する
フォームの送信が完了したら、利用者に送信完了を伝えるサンクスページへ遷移させます。
SSGformには、送信完了後の転送先URLを設定する機能があります。
今回は、サイト内にサンクスページを用意し、送信完了後にそのページへ遷移するように設定します。

サンクスページには、送信完了のメッセージに加えて、返信までの目安や、確認メールが届かない場合の案内などを掲載しておくとよいでしょう。
また、サンクスページは通常の検索結果に表示する必要がないため、noindexを設定しておきます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>お問い合わせ完了 | サンプルサイト</title>
<meta
name="robots"
content="noindex, nofollow"
>
<link rel="stylesheet" href="./css/thanks.css">
</head>
<body>
<header class="l-header">
<div class="l-container">
<a href="/">サンプルサイト</a>
</div>
</header>
<main id="main" class="l-main">
<div class="l-container">
<div class="c-thanks">
<h1>お問い合わせありがとうございます</h1>
<p>
お問い合わせを受け付けました。
</p>
<p>
ご入力いただいたメールアドレスに
確認メールをお送りしました。
ご確認ください。
</p>
<p>
内容を確認の上、
3営業日以内にご連絡いたします。
</p>
<p>
確認メールが届かない場合は、
迷惑メールフォルダもご確認ください。
</p>
<a href="/" class="c-thanks__button">
トップページへ戻る
</a>
</div>
</div>
</main>
<footer class="l-footer">
<div class="l-container">
<small>© サンプルサイト</small>
</div>
</footer>
</body>
</html>
参考まで、サンクスページのCSSも添付しておきます。
:root {
color-scheme: light;
font-family: system-ui, sans-serif;
line-height: 1.7;
color: #222;
background: #fff;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}
a {
color: #0759a3;
text-underline-offset: 0.2em;
}
:focus-visible {
outline: 3px solid #0759a3;
outline-offset: 3px;
}
/* Layout */
.l-container {
width: min(100% - 32px, 720px);
margin-inline: auto;
}
.l-header,
.l-footer {
padding-block: 24px;
background: #f5f5f5;
}
.l-main {
padding-block: 64px 96px;
}
/* Thanks */
.c-thanks {
text-align: center;
}
.c-thanks h1 {
margin: 0 0 32px;
font-size: clamp(1.75rem, 4vw, 2.25rem);
line-height: 1.4;
}
.c-thanks p {
margin: 0 0 24px;
}
.c-thanks__button {
display: inline-block;
min-width: 200px;
min-height: 48px;
margin-top: 32px;
padding: 12px 24px;
border: 2px solid #0759a3;
border-radius: 4px;
background: #0759a3;
color: #fff;
font-weight: 700;
text-decoration: none;
}
.c-thanks__button:hover {
background: #03447f;
}
@media (max-width: 600px) {
.l-main {
padding-block: 48px 64px;
}
.c-thanks__button {
width: 100%;
}
}
送信ボタンを押し、サンクスページに遷移することが確認できたら、実装は完了です。

【STEP 6】テスト送信して動作を確認する
最後に、フォームから実際に問い合わせを送信し、正常に動作するか確認します。
チェック項目
- 必須項目が未入力の場合、エラーが表示される
- メールアドレスの形式が不正な場合、エラーが表示される
- 入力内容を修正すると、エラー表示が適切に更新される
- 正常な入力内容でフォームを送信できる
- SSGformから通知メールが届く
- 通知メールに入力内容が正しく記載されている
- 送信完了後、サンクスページに遷移する
- 自動返信メールを設定した場合、送信者にメールが届く
また、実案件では、スマートフォンでの表示や操作、キーボードによる操作なども確認しておきましょう。
まとめ|SSGformはフォーム実装の選択肢の一つ
今回は、SSGformを使って問い合わせフォームを実装する方法を紹介しました。
SSGformを利用すれば、HTML・CSS・JavaScriptでフォームを自由に設計しながら、送信処理を外部サービスに任せることができます。
Astroなどの静的サイトジェネレーターだけでなく、純粋なHTMLサイトやWordPressでも利用できるため、Web制作者にとって選択肢の一つになるでしょう。
ただし、フォームを手軽に作成したい場合や、問い合わせをチームで管理したい場合には、ほかのフォームサービスの方が適していることもあります。
フォームの実装方法は、制作工数だけでなく、クライアントの運用体制や問い合わせの管理方法まで考えて選択することが重要です。
また、フォームが必要だからといって、サイト全体をWordPressで構築する必要はありません。
サイトの目的や運用方法に合わせて構築方式を選び、その環境に適したフォームを採用する。
SSGformは、そうした選択を可能にするサービスの一つです。
次回予告
SSGformでは問い合わせをメールで受け取ることができますが、件数が増えてくると、メールだけで管理するのは少し面倒になります。
そこで次回は、Google Apps Script(GAS)を使い、SSGformから届いた通知メールをGoogleスプレッドシートに自動集計する仕組みを紹介します。
ホームページの制作やリニューアル
サイト構成やCMS選定についてのご相談を承っています。
「WordPressが良いのか、Astroが良いのか」というご相談からでも問題ありません。
目的や運用体制に応じて、最適な構成をご提案します。
