Luxury Home Inquiry Form
Preview
Edit
Download
Run
Download Options
HTML File
Download as .html file
CSS File
Download as .css file
JavaScript File
Download as .js file
Combined HTML
All code in one HTML file
Project ZIP
All files in a ZIP archive
Cancel
HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Luxury Real Estate Inquiry</title> </head> <body> <div id="formWrapper" class="relative"> <div id="formContainer" class="form-container"> <div class="text-center mb-6"> <h1 class="text-3xl md:text-4xl font-bold text-slate-800 tracking-tight">Luxury Home Inquiry</h1> <p class="mt-2 text-slate-500 max-w-sm mx-auto">Please fill out the steps below and we'll connect you with a professional.</p> <div class="text-xs text-slate-400 mt-2"> Your User ID: <span id="userIdDisplay">Loading...</span> </div> </div> <div class="progress-bar-container"> <div id="progressBar" class="progress-bar"></div> </div> <form action="#" method="POST" class="space-y-6"> <!-- Step 1: Contact Information --> <div id="step1" class="form-step"> <h2 class="text-2xl font-semibold text-slate-700 mb-4">Step 1: Contact Details</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <div> <label for="full-name" class="block text-sm font-medium text-slate-700 mb-1">Full Name</label> <input type="text" id="full-name" name="full-name" required placeholder="Jane Doe" class="input-field placeholder-slate-400"> </div> <div> <label for="email" class="block text-sm font-medium text-slate-700 mb-1">Email Address</label> <input type="email" id="email" name="email" required placeholder="you@example.com" class="input-field placeholder-slate-400"> </div> </div> <div class="mt-6"> <label for="phone" class="block text-sm font-medium text-slate-700 mb-1">Phone Number</label> <input type="tel" id="phone" name="phone" placeholder="(123) 456-7890" class="input-field placeholder-slate-400"> </div> </div> <!-- Step 2: Inquiry Details --> <div id="step2" class="form-step hidden-element"> <h2 class="text-2xl font-semibold text-slate-700 mb-4">Step 2: Property Preferences</h2> <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <div> <label for="property-type" class="block text-sm font-medium text-slate-700 mb-1">Property Type</label> <select id="property-type" name="property-type" class="input-field placeholder-slate-400" required> <option value="" disabled selected>Select a type</option> <option value="single-family">Single-Family Home</option> <option value="condo">Condo / Apartment</option> <option value="townhouse">Townhouse</option> <option value="land">Land</option> </select> </div> <div> <label for="budget" class="block text-sm font-medium text-slate-700 mb-1">Budget Range</label> <select id="budget" name="budget" class="input-field placeholder-slate-400" required> <option value="" disabled selected>Select a range</option> <option value="100k-500k">$100k - $500k</option> <option value="500k-1m">$500k - $1M</option> <option value="1m-5m">$1M - $5M</option> <option value="5m+">$5M+</option> </select> </div> </div> <div class="mt-6"> <label for="location" class="block text-sm font-medium text-slate-700 mb-1">Preferred Location</label> <input type="text" id="location" name="location" required placeholder="e.g., San Francisco, CA" class="input-field placeholder-slate-400"> </div> </div> <!-- Step 3: Message --> <div id="step3" class="form-step hidden-element"> <h2 class="text-2xl font-semibold text-slate-700 mb-4">Step 3: Your Message</h2> <label for="message" class="block text-sm font-medium text-slate-700 mb-1">Your Message</label> <textarea id="message" name="message" rows="4" required placeholder="I'm interested in properties with at least 4 bedrooms and a large backyard in the suburbs..." class="input-field placeholder-slate-400"></textarea> </div> <!-- Navigation Buttons --> <div class="flex justify-between pt-2"> <button type="button" id="backBtn" class="nav-button bg-gray-200 text-gray-700 font-semibold py-3 px-6 rounded-xl hover:bg-gray-300"> Back </button> <button type="button" id="nextBtn" class="nav-button bg-blue-600 text-white font-semibold py-3 px-6 rounded-xl hover:bg-blue-700"> Next Step </button> </div> <!-- Submit Button for the last step --> <div class="hidden-element pt-2" id="finalStepButtons"> <button type="submit" id="submitBtn" class="submit-button w-full bg-blue-600 text-white font-semibold py-4 px-4 rounded-xl hover:bg-blue-700 focus:outline-none focus:ring-4 focus:ring-blue-500 focus:ring-opacity-50 text-lg"> <span id="buttonText" class="button-text">Send Inquiry</span> <div id="buttonSpinner" class="button-spinner mx-auto hidden"></div> </button> </div> </form> <div id="messageBox" class="hidden mt-4 p-3 rounded-xl text-center font-medium shadow-lg transition-all duration-300"> <p id="messageText"></p> </div> </div> <!-- Hidden success screen --> <div id="successScreen" class="absolute inset-0 flex flex-col justify-center items-center text-center text-slate-700 bg-white rounded-2xl p-8 opacity-0 pointer-events-none"> <svg id="checkmarkIcon" class="checkmark-icon text-green-500 w-20 h-20 mb-4" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M5 13L9 17L19 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </svg> <h2 class="text-3xl font-extrabold mb-2">Inquiry Sent!</h2> <p class="text-lg text-slate-500">Thank you for your interest. Your inquiry has been saved successfully.</p> </div> </div> </body> </html>
CSS
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'); body { font-family: 'Inter', sans-serif; background: #f8fafc; background: radial-gradient(circle at top right, #e2e8f0 0%, transparent 50%), radial-gradient(circle at bottom left, #dbeafe 0%, transparent 50%), #f8fafc; display: flex; justify-content: center; align-items: center; min-height: 100vh; padding: 2rem; overflow: hidden; transition: background-color 0.5s ease-in-out; } .form-container { background-color: rgba(255, 255, 255, 0.9); backdrop-filter: blur(10px) saturate(180%); -webkit-backdrop-filter: blur(10px) saturate(180%); border: 1px solid rgba(255, 255, 255, 0.3); border-radius: 2rem; box-shadow: 0 15px 35px rgba(0, 0, 0, 0.1), 0 5px 15px rgba(0, 0, 0, 0.05); padding: 3rem; width: 100%; max-width: 40rem; transform: scale(1); transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1); } .progress-bar-container { height: 8px; background-color: #e5e7eb; border-radius: 9999px; overflow: hidden; margin-bottom: 2rem; } .progress-bar { height: 100%; width: 0%; background-color: #2563eb; transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1); } .input-field { width: 100%; padding: 0.85rem 1.25rem; border: 1px solid #cbd5e1; border-radius: 1rem; background-color: #f1f5f9; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.06); } .input-field:focus { outline: none; border-color: #2563eb; box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.2); background-color: #ffffff; } .submit-button, .nav-button { transition: all 0.3s ease; box-shadow: 0 4px 12px rgba(37, 99, 235, 0.2); position: relative; overflow: hidden; } .submit-button:hover, .nav-button:hover { transform: translateY(-2px); box-shadow: 0 8px 18px rgba(37, 99, 235, 0.3); } .submit-button::before, .nav-button::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent); transition: left 0.5s ease; } .submit-button:hover::before, .nav-button:hover::before { left: 100%; } .button-text { transition: opacity 0.3s ease; } .button-spinner { display: none; border: 4px solid rgba(255, 255, 255, 0.3); border-top: 4px solid #ffffff; border-radius: 50%; width: 24px; height: 24px; animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } #successScreen { transform: scale(0.8); opacity: 0; transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1); } .checkmark-icon { transform: scale(0); animation: checkmark-bounce 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; animation-delay: 0.5s; } @keyframes checkmark-bounce { 0% { transform: scale(0); } 60% { transform: scale(1.1); } 100% { transform: scale(1); } } .animate-fade-in { animation: fadeIn 0.8s ease-out; } @keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } .hidden-element { display: none; }
JavaScript
import { initializeApp } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-app.js"; import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-auth.js"; import { getFirestore, collection, addDoc, setLogLevel } from "https://www.gstatic.com/firebasejs/11.6.1/firebase-firestore.js"; // --- Firebase Setup --- // DO NOT EDIT - These global variables are provided by the canvas environment. const appId = typeof __app_id !== 'undefined' ? __app_id : 'default-app-id'; const firebaseConfig = typeof __firebase_config !== 'undefined' ? JSON.parse(__firebase_config) : {}; const initialAuthToken = typeof __initial_auth_token !== 'undefined' ? __initial_auth_token : null; let db, auth; let userId; const initFirebase = async () => { if (Object.keys(firebaseConfig).length > 0) { const app = initializeApp(firebaseConfig); db = getFirestore(app); auth = getAuth(app); setLogLevel('Debug'); onAuthStateChanged(auth, async (user) => { if (user) { userId = user.uid; document.getElementById('userIdDisplay').textContent = userId; console.log("Firebase Auth State Changed. User ID:", userId); } else { // User is signed out. Sign in anonymously. try { if (initialAuthToken) { await signInWithCustomToken(auth, initialAuthToken); } else { await signInAnonymously(auth); } } catch (error) { console.error("Firebase auth error:", error); } } }); } else { console.error("Firebase config is missing. The app will not save data."); } }; // --- Multi-step Form Logic --- let currentStep = 1; const formSteps = document.querySelectorAll('.form-step'); const progressBar = document.getElementById('progressBar'); const submitButton = document.getElementById('submitBtn'); const buttonText = document.getElementById('buttonText'); const buttonSpinner = document.getElementById('buttonSpinner'); const formContainer = document.getElementById('formContainer'); const successScreen = document.getElementById('successScreen'); const formWrapper = document.getElementById('formWrapper'); // Hide all steps except the first one formSteps.forEach((step, index) => { if (index > 0) step.style.display = 'none'; }); const updateFormState = () => { // Update progress bar const progress = (currentStep - 1) / (formSteps.length - 1) * 100; progressBar.style.width = `${progress}%`; // Show/hide steps formSteps.forEach((step, index) => { step.style.display = 'none'; if (index === currentStep - 1) { step.style.display = 'block'; step.classList.add('animate-fade-in'); } else { step.classList.remove('animate-fade-in'); } }); // Update button text if (currentStep < formSteps.length) { submitButton.textContent = 'Next Step'; } else { submitButton.textContent = 'Send Inquiry'; } }; const validateStep = (step) => { const inputs = formSteps[step - 1].querySelectorAll('input[required], select[required], textarea[required]'); for (let input of inputs) { if (!input.value) { return false; } } return true; }; document.getElementById('nextBtn').addEventListener('click', () => { if (validateStep(currentStep)) { if (currentStep < formSteps.length) { currentStep++; updateFormState(); } } else { showMessageBox('Please fill out all required fields.', 'red'); } }); document.getElementById('backBtn').addEventListener('click', () => { if (currentStep > 1) { currentStep--; updateFormState(); } }); // Combined form submission listener for the last step document.querySelector('form').addEventListener('submit', async (event) => { event.preventDefault(); if (currentStep !== formSteps.length) return; if (!validateStep(currentStep)) { showMessageBox('Please fill out all required fields.', 'red'); return; } // Show loading state buttonText.style.opacity = '0'; buttonSpinner.style.display = 'block'; submitButton.disabled = true; // Collect form data const formData = { fullName: document.getElementById('full-name').value, email: document.getElementById('email').value, phone: document.getElementById('phone').value, propertyType: document.getElementById('property-type').value, budget: document.getElementById('budget').value, location: document.getElementById('location').value, message: document.getElementById('message').value, submittedAt: new Date().toISOString() }; console.log("Submitting form data:", formData); // Attempt to save data to Firebase try { if (!db || !userId) { throw new Error("Firebase not initialized or user not authenticated."); } const inquiryCollection = collection(db, `artifacts/${appId}/users/${userId}/inquiries`); await addDoc(inquiryCollection, formData); // Success console.log("Inquiry successfully saved to Firestore."); // Hide the form and show success screen formContainer.classList.add('opacity-0', 'scale-90'); formContainer.classList.remove('scale-100'); setTimeout(() => { formContainer.style.display = 'none'; successScreen.classList.remove('pointer-events-none'); successScreen.style.opacity = '1'; successScreen.style.transform = 'scale(1)'; }, 500); } catch (error) { console.error("Error saving to Firestore:", error); showMessageBox("Something went wrong. Please try again.", 'red'); submitButton.disabled = false; buttonText.style.opacity = '1'; buttonSpinner.style.display = 'none'; } }); // General message box function (replaces alert) function showMessageBox(message, type) { const messageBox = document.getElementById('messageBox'); const messageText = document.getElementById('messageText'); messageText.innerText = message; messageBox.className = `mt-4 p-3 rounded-xl text-center font-medium shadow-lg transition-all duration-300`; if (type === 'red') { messageBox.classList.add('bg-red-100', 'text-red-800'); } else { messageBox.classList.add('bg-green-100', 'text-green-800'); } messageBox.classList.remove('hidden'); messageBox.style.opacity = '1'; setTimeout(() => { messageBox.style.opacity = '0'; setTimeout(() => messageBox.classList.add('hidden'), 300); }, 3000); } // Initialize Firebase on window load window.onload = initFirebase;
Output Preview
Desktop
Mobile
Fullscreen