Vue Forms
Building forms in Vue 3 is clean and declarative. By using the Composition API (<script setup>), we can bind form values with reactive states (ref or reactive) and submit submissions asynchronously to Lucid Forms.
AI Prompt (Cursor, Claude, v0, ChatGPT)
Section titled “AI Prompt (Cursor, Claude, v0, ChatGPT)”If you are building your Vue application with an AI assistant (such as Cursor, Claude, v0, Windsurf, or ChatGPT), copy and paste this prompt to generate a Vue 3 component:
Create a responsive Vue 3 contact form component using <script setup> and the Composition API.
Submission Endpoint:https://api.lucidforms.co/f/{your-form-id}
Requirements:- Fields: Name, Email, and Message with reactive two-way bindings (v-model or reactive state)- Include an invisible honeypot field (_honeypot) for spam bot detection- Submit form data asynchronously using fetch() to the submission endpoint with 'Accept: application/json' and 'Content-Type: application/json'- Provide reactive UI states: idle, loading (disable submit button), success message, and error alerts- Reset form inputs on successful submission- Style with modern, responsive Tailwind CSS classesSingle File Component (SFC) Example
Section titled “Single File Component (SFC) Example”Here is a full Vue 3 template that captures form input and submits it without reloading the browser window.
<script setup>import { ref, reactive } from 'vue'
const form = reactive({ name: '', email: '', message: '', _honeypot: '' // Spam trap})
const status = ref('idle') // 'idle' | 'loading' | 'success' | 'error'const errorMessage = ref('')
const handleSubmit = async () => { status.value = 'loading' errorMessage.value = ''
// Honeypot spam check if (form._honeypot) { status.value = 'success' return }
try { const response = await fetch('https://api.lucidforms.co/f/{your-form-id}', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ name: form.name, email: form.email, message: form.message }) })
const responseData = await response.json()
if (response.ok) { status.value = 'success' // Reset form form.name = '' form.email = '' form.message = '' } else { status.value = 'error' errorMessage.value = responseData.error || 'Form submission failed.' } } catch (err) { status.value = 'error' errorMessage.value = 'A network error occurred. Please try again.' }}</script>
<template> <div class="form-container"> <h2>Contact Us</h2>
<div v-if="status === 'success'" class="alert-success"> ✓ Thank you! Your submission was received successfully. </div>
<div v-if="status === 'error'" class="alert-error"> ✗ {{ errorMessage }} </div>
<form @submit.prevent="handleSubmit"> <!-- Invisible spam field --> <input type="text" v-model="form._honeypot" class="hidden-honeypot" tabindex="-1" autocomplete="off" />
<div class="form-group"> <label for="name">Name</label> <input type="text" id="name" v-model="form.name" required /> </div>
<div class="form-group"> <label for="email">Email</label> <input type="email" id="email" v-model="form.email" required /> </div>
<div class="form-group"> <label for="message">Message</label> <textarea id="message" v-model="form.message" required rows="4"></textarea> </div>
<button type="submit" :disabled="status === 'loading'"> {{ status === 'loading' ? 'Sending...' : 'Send Message' }} </button> </form> </div></template>
<style scoped>.form-container { max-width: 400px; margin: 0 auto; font-family: system-ui, sans-serif;}.form-group { margin-bottom: 15px;}label { display: block; margin-bottom: 5px; font-weight: 500;}input[type="text"],input[type="email"],textarea { width: 100%; padding: 8px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box;}.hidden-honeypot { display: none;}button { padding: 10px 15px; background-color: #42b883; color: white; border: none; border-radius: 4px; cursor: pointer;}button:disabled { opacity: 0.6;}.alert-success { color: #2e7d32; background-color: #e8f5e9; padding: 10px; border-radius: 4px; margin-bottom: 15px;}.alert-error { color: #c62828; background-color: #ffebee; padding: 10px; border-radius: 4px; margin-bottom: 15px;}</style>
