NewtとNuxt3を利用して、問い合わせフォームを作成する
Table of contents
- 記事内で使用している主なソフトウェアのバージョン
- 前提条件
- 概要
- 1. Form Appを作成する
- 1-1. Form Appの追加
- 1-2. フォームの作成
- 2. Nuxt3でシンプルな問い合わせフォームを作成する
- 2-1. HTMLフォームの追加
- 2-2. 自動返信メールの設定
- 2-3. 受信通知メールの設定
- 2-4. 挙動の確認
- 3. バリデーションを追加する
- 3-1. input要素の属性を利用したバリデーション
- 3-2. JavaScriptを利用したバリデーション
- 4. スパム対策を実装する
- 4-1. サイトキーとシークレットキーの取得
- 4-2. シークレットキーの登録
- 4-3. Nuxtでの設定
- 5. リダイレクトをカスタマイズする
- 5-1. 送信成功ページ・送信失敗ページを用意する
- 5-2. リダイレクトを設定する
このチュートリアルでは、Newtの Form App と Nuxt3 を利用して、問い合わせフォームを作成する手順を紹介します。
記事内で使用している主なソフトウェアのバージョン
- Nuxt(
nuxt
): 3.2.0 - VeeValidate(
vee-validate
): 4.7.4 - Vue reCAPTCHA-v3(
vue-recaptcha-v3
): 2.0.1
前提条件
- Nuxt3のプロジェクトを作成済みであること
Nuxt3のセットアップについて知りたい場合は、以下のドキュメントをご確認ください。
- Nuxtの Installation のドキュメント
- NewtとNuxt3を利用してブログを作成する
概要
Nuxt3で問い合わせフォームを作成し、Newtで問い合わせデータを確認できるようにします。
はじめに、自動返信・受信通知のついたシンプルなフォームを作成し、その後でバリデーション・スパム対策・リダイレクトの処理を実装しながら、カスタマイズの方法を学習していきます。
※ ここではスタイルについては扱いません。スタイルについて確認したい方は、Next.jsのコードとなりますが、問い合わせ用のテンプレート newt-starter-nextjs-contact を用意しているので、そちらのコードをご確認ください。
1. Form Appを作成する
はじめに、NewtでForm Appを作成します。
1-1. Form Appの追加
「Appを追加」をクリックして「タイプを選択して追加」を選択します。
「Form App」を選択して「追加」をクリックします。
App名・App UID・Appアイコンを設定して「追加」をクリックします。
これで「Contact」という名前のForm Appが追加されました。
1-2. フォームの作成
次にフォームを作成します。「フォームを作成」ボタンをクリックし、名前を付けてフォームを作成します。
作成後に表示されるエンドポイントは、2-1で利用します。
2. Nuxt3でシンプルな問い合わせフォームを作成する
続いて、Nuxt3でシンプルな問い合わせフォームを作成しましょう。
ここでは /contact
というパスにアクセスした時に、問い合わせフォームを表示するようにします。
2-1. HTMLフォームの追加
pages/contact.vue
を作成し、以下のように記述します。
form
の action
属性に設定している https://xxxxxx.form.newt.so/v1/xxxxxx
の値については、1-2で確認したエンドポイントの値に置き換えてください。
<!-- pages/contact.vue -->
<script lang="ts" setup>
useHead({
title: 'Newt・Nuxtフォーム',
meta: [
{ name: 'description', content: 'NewtとNuxtを利用した問い合わせフォームです' }
]
})
</script>
<template>
<div>
<h1>Contact us</h1>
<form action="https://xxxxxx.form.newt.so/v1/xxxxxx" method="post">
<label for="name">Name</label>
<input id="name" name="name">
<label for="email">Email</label>
<input id="email" name="email" type="email">
<label for="message">Message</label>
<textarea id="message" name="message" />
<button type="submit">
Submit
</button>
</form>
</div>
</template>
各属性について説明します。
label要素のfor属性と、input要素・textarea要素のid属性
label要素 の for
属性は、input要素 や textarea要素 の id
属性と一致するように設定します。
input要素・textarea要素のname属性
input要素・textarea要素のnameで設定された値をもとに、投稿データのスキーマが決まります。例えば上記の例では、name
・email
・message
フィールドを持ったスキーマが作成されます。
詳細については、フィールドの仕様 のドキュメントをご確認ください。
input要素のtype属性
お好みの入力形式に応じて、inputの型 を選択してください。デフォルトでは text
となります。
これで http://localhost:3000/contact
にアクセスすると、以下のような問い合わせフォームが作成できました。
※ スタイルについてはお好みで設定してください
2-2. 自動返信メールの設定
自動返信メール の設定をします。自動返信メールを設定することで、投稿を送信したエンドユーザーに対して、設定した内容のメールを自動で送信できます。
※ Newtは自動返信メールの送信先メールアドレスを検出するために email
フィールドを使います。input要素のname属性に email
を指定し、エンドユーザーのメールアドレスが入力されるようにしてください。
「App設定」から該当のフォームをクリックし、「メール設定」を選択します。
「自動返信メールを有効にする」にチェックを入れ、件名と本文を入力し、「保存」をクリックします。
自動返信メールでは {submission.name}
のように記述することで、メールの件名や本文に、投稿データの内容を埋め込めます。
2-1で、input要素・textarea要素のname属性に name
・email
・message
を指定したので、ここでは {submission.name}
・{submission.email}
・{submission.message}
を利用できます。
2-3. 受信通知メールの設定
受信通知メール の設定をします。受信通知メールを設定することで、エンドユーザーから新しいメッセージを受信した際に、メールで通知を受け取れます。
「App設定」から該当のフォームをクリックし、「メール設定」を選択します。
「受信通知メールを有効にする」にチェックを入れ、通知を受け取るメールアドレス・件名・本文を設定し、「保存」をクリックします。
受信通知メールでも、自動返信メールと同様に、投稿データの内容を埋め込めます。
2-4. 挙動の確認
これで、シンプルな問い合わせフォームを作成できました。
実際に動かして、挙動を確認してみましょう。
まず、開発サーバーを立ち上げて、問い合わせフォームを表示します。ここでは http://localhost:3000/contact
にアクセスします。
適当な内容を入力して送信すればよいですが、設定したEmail(name属性に email
を指定した入力値)に自動返信メールが届くので、ご自身のメールアドレスを入力するよう気をつけてください。
送信が成功すると、以下の画面が表示されます。
管理画面では、以下のようにデータが確認できます。
次に自動返信メールを確認します。以下のようなメールが飛んでいれば成功です。
最後に受信通知メールを確認します。以下のようなメールが飛んでいれば成功です。
これでシンプルなフォームの作成・自動返信メールの設定・受信通知メールの設定ができました。ここからはフォームのカスタマイズをしながら、より高度なフォームの作成方法を学んでいきましょう。
3. バリデーションを追加する
クライアントサイドのバリデーションについて、以下の順で紹介します。
- input要素の属性を利用したバリデーション
- JavaScriptを利用したバリデーション(VeeValidateを利用したバリデーション)
3-1. input要素の属性を利用したバリデーション
HTML5のフォームバリデーションを利用することで、JavaScriptなしでバリデーションを実行できます。よく使われるものについては HTML5のフォームバリデーション をご確認ください。
例えば、name
を必須にしたい場合は、以下のように required
を指定します。
<input id="name" name="name" required />
もし name
を指定せず、送信を実行した場合は、以下のように表示されます。
3-2. JavaScriptを利用したバリデーション
HTMLネイティブのフォームバリデーションでは足りない場合、JavaScriptを利用することで、より柔軟なバリデーションを実行できます。
ここでは、バリデーションのタイミングを変え、さらにエラーメッセージをカスタマイズしてみましょう。
デフォルトのThanksページ・Errorページへのリダイレクトや カスタムリダイレクト は行われなくなりますので、ご注意ください。
ここでは VeeValidate を利用してバリデーションを行います。まずは vee-validate をインストールしましょう。
npm install vee-validate
# or
yarn add vee-validate
続いて、以下のように pages/contact.vue
を修正します。
※ fetch
の リソースとして設定されている https://xxxxxx.form.newt.so/v1/xxxxxx
の値については、1-2で確認したエンドポイントの値に置き換えてください。
<!-- pages/contact.vue -->
<script lang="ts" setup>
import { useForm } from 'vee-validate'
const schema = {
name (value: string) {
if (!value) {
return 'Name is required'
}
return true
}
}
const { useFieldModel, handleSubmit, errors } = useForm({
validationSchema: schema
})
const [name, email, message] = useFieldModel(['name', 'email', 'message'])
const onSubmit = handleSubmit(async (values) => {
const formData = new FormData()
Object.entries(values).forEach(([key, value]) => {
formData.append(key, value)
})
await fetch('https://xxxxxx.form.newt.so/v1/xxxxxx', {
method: 'POST',
body: formData,
headers: {
Accept: 'application/json'
}
})
})
useHead({
title: 'Newt・Nuxtフォーム',
meta: [
{ name: 'description', content: 'NewtとNuxtを利用した問い合わせフォームです' }
]
})
</script>
<template>
<div>
<h1>Contact us</h1>
<form @submit="onSubmit">
<label for="name">Name*</label>
<input id="name" v-model="name" name="name" aria-describedby="error-name-required">
<span v-if="errors.name" id="error-name-required" aria-live="assertive">
{{ errors.name }}
</span>
<label for="email">Email</label>
<input id="email" v-model="email" name="email" type="email">
<label for="message">Message</label>
<textarea id="message" v-model="message" name="message" />
<button type="submit">
Submit
</button>
</form>
</div>
</template>
以下のことを行っています。
validationSchema
に渡すschema
で、name
がない場合にName is required
というエラーメッセージを設定しています- 入力されたフォームのデータは handleSubmit 関数で
values
として利用できます - FormData を利用して、送信するデータ
formData
を作成します - フェッチ API を利用して、1-2で確認したエンドポイントにデータを送ります。この時、Acceptヘッダーに
'application/json'
を指定します
また、以下の部分で validationSchema
で設定したエラーメッセージを出しています。(ここでは name
がない場合に Name is required
というエラーメッセージを出しています)
validationSchema
を利用して、様々なバリデーションが設定できるので、ぜひお好きなバリデーションをお試しください。
<label for="name">Name*</label>
<input id="name" v-model="name" name="name" aria-describedby="error-name-required">
<span v-if="errors.name" id="error-name-required" aria-live="assertive">
{{ errors.name }}
</span>
以下のことを確認します。
- 入力変更があったタイミングでバリデーションが実行されること
name
が入力されていない場合にName is required
というエラーメッセージが出ること
4. スパム対策を実装する
続いて、スパム対策 として Google reCAPTCHA v3 の設置方法について説明します。
4-1. サイトキーとシークレットキーの取得
Google reCAPTHAのコンソール にアクセスし、新しいサイトを登録します。
reCAPTCHAタイプは reCAPTCHA v3
を選択します。
ここではローカル環境でのテストを行うので、ドメインには localhost
を追加します。本番環境で設定したい場合は、reCAPTCHAを導入したいサイトのドメインを設定してください。
全ての項目を入力して「送信」をクリックすると、サイトキーとシークレットキーが表示されます。
4-2. シークレットキーの登録
Newtの管理画面にアクセスし、「App設定」を開きます。該当のフォームをクリックし、「フォーム設定」を選択します。
「スパム対策」のセクションより、「Google reCAPTCHA v3を有効にする」にチェックを入れ、4-1で取得したシークレットキーを貼り付けて保存します。
4-3. Nuxtでの設定
最後にNuxtでの設定を行います。ここでは Vue reCAPTCHA-v3 を用いて、設定します。まずはvue-recaptcha-v3をインストールしましょう。
npm install vue-recaptcha-v3
# or
yarn add vue-recaptcha-v3
3-2で作成した pages/contact.vue
を、以下のように修正します。
siteKey
に設定している reCAPTCHA_site_key
のところは、4-1で取得したサイトキーを入力してください。
<script lang="ts" setup>
import { useForm } from 'vee-validate'
+ import { VueReCaptcha, useReCaptcha } from 'vue-recaptcha-v3'
const schema = {
name (value: string) {
if (!value) {
return 'Name is required'
}
return true
}
}
const { useFieldModel, handleSubmit, errors } = useForm({
validationSchema: schema
})
const [name, email, message] = useFieldModel(['name', 'email', 'message'])
+ const { vueApp } = useNuxtApp()
+ vueApp.use(VueReCaptcha, {
+ siteKey: 'reCAPTCHA_site_key',
+ loaderOptions: {
+ renderParameters: {
+ hl: 'ja'
+ }
+ }
+ })
+ const recaptchaInstance = useReCaptcha()
const onSubmit = handleSubmit(async (values) => {
+ await recaptchaInstance?.recaptchaLoaded()
+ const token = await recaptchaInstance?.executeRecaptcha('submit')
+ values.googleReCaptchaToken = token
const formData = new FormData()
Object.entries(values).forEach(([key, value]) => {
formData.append(key, value)
})
await fetch('https://xxxxxx.form.newt.so/v1/xxxxxx', {
method: 'POST',
body: formData,
headers: {
Accept: 'application/json'
}
})
})
useHead({
title: 'Newt・Nuxtフォーム',
meta: [
{ name: 'description', content: 'NewtとNuxtを利用した問い合わせフォームです' }
]
})
</script>
<template>
(省略)
</template>
以下のことを行っています。
VueReCaptcha
とuseReCaptcha
をインポートしますVueReCaptcha
の オプション として、siteKey
とloaderOptions
を設定しています。ここではhl
にja
を設定しているため、問い合わせフォームの右下に表示されるreCAPTCHAのバッジが日本語になります。他の言語で設定したい方は、Googleの Language Codes のドキュメントを参考に設定してくださいgoogleReCaptchaToken
というフィールド名でトークンを送信します
これでGoogle reCAPTCHA v3によるスパム対策が実装できました。
もし、バッジを非表示にしたい場合、loaderOptions.autoHideBadge
を true
にすると非表示になりますが、この操作はGoogle公式のガイドに従った場合のみ許可されます。
詳細は、Googleの reCAPTCHA バッジを非表示にします。どうすればよいですか? のドキュメントをご確認ください。
5. リダイレクトをカスタマイズする
最後にフォーム送信後のリダイレクトをカスタマイズします。
送信が成功した場合のページと、失敗した場合のページを用意して、送信結果に応じてリダイレクトしてみましょう。
5-1. 送信成功ページ・送信失敗ページを用意する
送信成功ページとして、以下を用意します。
page/thanks.vue
を作成します。
<!-- pages/thanks.vue -->
<script lang="ts" setup>
useHead({
title: 'Thank you',
meta: [
{ name: 'description', content: '問い合わせの送信が成功しました' }
]
})
</script>
<template>
<div className="Result">
<h1>Thank you!</h1>
<div>
<NuxtLink href="/contact">
Back to Previous Page
</NuxtLink>
</div>
</div>
</template>
送信失敗ページとして、以下を用意します。
page/error.vue
を作成します。
<!-- pages/error.vue -->
<script lang="ts" setup>
useHead({
title: 'Error',
meta: [
{ name: 'description', content: '問い合わせの送信が失敗しました' }
]
})
</script>
<template>
<div className="Result">
<h1>Error!</h1>
<div>
<NuxtLink href="/contact">
Back to Previous Page
</NuxtLink>
</div>
</div>
</template>
5-2. リダイレクトを設定する
page/contact.vue
を以下のように修正します。
※ fetch
の リソースとして設定されている https://xxxxxx.form.newt.so/v1/xxxxxx
の値については、1-2で確認したエンドポイントの値に置き換えてください。
<script lang="ts" setup>
(省略)
const onSubmit = handleSubmit(async (values) => {
await recaptchaInstance?.recaptchaLoaded()
const token = await recaptchaInstance?.executeRecaptcha('submit')
values.googleReCaptchaToken = token
const formData = new FormData()
Object.entries(values).forEach(([key, value]) => {
formData.append(key, value)
})
- await fetch('https://xxxxxx.form.newt.so/v1/xxxxxx', {
- method: 'POST',
- body: formData,
- headers: {
- Accept: 'application/json'
- }
- })
+ try {
+ const response = await fetch('https://xxxxxx.form.newt.so/v1/xxxxxx', {
+ method: 'POST',
+ body: formData,
+ headers: {
+ Accept: 'application/json'
+ }
+ })
+
+ if (response.ok) {
+ await navigateTo('/thanks')
+ } else {
+ await navigateTo('/error')
+ }
+ } catch (err) {
+ await navigateTo('/error')
+ }
})
(省略)
</script>
<template>
(省略)
</template>
送信が成功した場合(response.ok がtrueの場合)は navigateTo を利用して /thanks
にリダイレクトし、送信成功ページを表示しています。
送信が失敗した場合(response.ok がfalseの場合、またはエラーが発生した場合)は /error
にリダイレクトし、送信失敗ページを表示しています。
これでリダイレクトをカスタマイズすることができました。
以上で、すべてのステップが終了となります。
Form Appでは、他にもさまざまな機能があるので、興味のある方はぜひ以下のドキュメントもご覧ください。