<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>

<div x-data='formValidation'>
  <form @submit.prevent='validateForm'>
    <div class='inner'>
      <div>
        <label for='name'>お名前:</label>
        <div>
          <input type='text' id='name' x-model='name' @blur='validateName' />
        </div>
        <p x-show='errors.name' x-text='errors.name' class="error">
        </p>
      </div>

      <div>
        <label for='phone'>電話番号:</label>
        <div>
          <input type='text' id='phone' x-model='phone' @blur=' validatePhone' />
        </div>
        <p x-show='errors.phone' x-text='errors.phone' class="error">
        </p>
      </div>

      <div>
        <label for='email'>メールアドレス:</label>
        <div>
          <input type='email' id='email' x-model='email' @blur='validateEmail' />
        </div>
        <p x-show='errors.email' x-text='errors.email' class="error">
        </p>
      </div>

      <div>
        <label for='inquiry'>お問い合わせ内容:</label>
        <div>
          <textarea id='inquiry' x-model='inquiry' @blur='validateInquiry'>
              </textarea>
        </div>
        <p x-show='errors.inquiry' x-text='errors.inquiry' class="error">
        </p>
      </div>
    </div>
    <button type='submit' class='submit-btn'>送信</button>
  </form>
</div>
.inner {
  display: grid;
  row-gap: 20px;
}

.error {
  color: red;
  font-size: 14px;
  margin: 8px 0 0;
}

.submit-btn {
  margin-top: 42px;
}
document.addEventListener('alpine:init', () => {
  Alpine.data('formValidation', () => ({
    name: '',
    phone: '',
    email: '',
    inquiry: '',
    errors: {},

    validateName() {
      if (!this.name) {
        this.errors.name = '※お名前は必須です。'
      } else {
        delete this.errors.name
      }
    },

    validatePhone() {
      const phonePattern = /^\d{2,4}-?\d{2,4}-?\d{4}$/
      if (!this.phone) {
        this.errors.phone = '※電話番号は必須です。'
      } else if (!phonePattern.test(this.phone)) {
        this.errors.phone = '※有効な電話番号を入力してください。'
      } else {
        delete this.errors.phone
      }
    },

    validateEmail() {
      const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
      if (!this.email) {
        this.errors.email = '※メールアドレスは必須です。'
      } else if (!emailPattern.test(this.email)) {
        this.errors.email = '※有効なメールアドレスを入力してください。'
      } else {
        delete this.errors.email
      }
    },

    validateInquiry() {
      if (!this.inquiry) {
        this.errors.inquiry = '※お問い合わせ内容は必須です。'
      } else {
        delete this.errors.inquiry
      }
    },

    validateForm() {
      this.validateName()
      this.validateEmail()
      this.validatePhone()
      this.validateInquiry()

      if (Object.keys(this.errors).length === 0) {
        alert('フォームが送信されました!')
      } else {
        alert('入力に誤りがあります。')
      }
    },
  }))
})
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.