From d742364f46b1e4b8c0b2e4e9c0a5a907dd14d627 Mon Sep 17 00:00:00 2001 From: dereklseitz Date: Sat, 16 Aug 2025 08:09:53 -0500 Subject: [PATCH] feat(contact-form): enhance validation and accessibility --- src/about.njk | 28 ++++++---- src/scripts/accordion.js | 11 +++- src/scripts/contact-form.js | 102 ++++++++++++++++++++++-------------- src/styles/about.css | 27 ++++++++-- 4 files changed, 117 insertions(+), 51 deletions(-) diff --git a/src/about.njk b/src/about.njk index cbace84..0277f5a 100644 --- a/src/about.njk +++ b/src/about.njk @@ -54,31 +54,37 @@ pageScripts: Contact Info
- + +
- + + +
- + +
- + +
- + +
-
-

Preferred Contact Method

+
+

Preferred Contact Method

* Required fields

diff --git a/src/scripts/accordion.js b/src/scripts/accordion.js index 5929f31..08e9f7f 100644 --- a/src/scripts/accordion.js +++ b/src/scripts/accordion.js @@ -2,6 +2,7 @@ document.addEventListener('DOMContentLoaded', (event) => { const accordionHeaders = document.querySelectorAll('.accordion-header'); accordionHeaders.forEach(header => { + // Toggle content on click header.addEventListener('click', () => { const content = header.nextElementSibling; if (content.style.display === 'block') { @@ -10,5 +11,13 @@ document.addEventListener('DOMContentLoaded', (event) => { content.style.display = 'block'; } }); + + // Toggle content on Enter or Space key press + header.addEventListener('keydown', (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + header.click(); + } + }); }); -}); \ No newline at end of file +}); diff --git a/src/scripts/contact-form.js b/src/scripts/contact-form.js index 287bf7b..05379d8 100644 --- a/src/scripts/contact-form.js +++ b/src/scripts/contact-form.js @@ -1,68 +1,94 @@ // Contact Form Submission Script -// Select Form Element const form = document.getElementById("contact-form"); +const resetButton = form.querySelector('button[type="reset"]'); -// Event Listener for Submit Event -form.addEventListener('submit', function(event) { - event.preventDefault(); // Prevent default form submission - // Variable Assignments - const firstName = document.getElementById('first-name').value.trim(); - const lastName = document.getElementById('last-name').value.trim(); - const organization = document.getElementById('organization').value.trim(); // Fixed typo - const email = document.getElementById('email').value.trim(); - const phone = document.getElementById('phone').value.trim(); +// Utility: Show error for specific input +function showError(inputId, message) { + const input = document.getElementById(inputId); + const errorSpan = document.getElementById(`${inputId}-error`); + if (input) input.classList.add("error"); + if (errorSpan) errorSpan.textContent = message; +} + +// Utility: Clear all errors +function clearErrors() { + document.querySelectorAll(".error-message").forEach(span => span.textContent = ""); + document.querySelectorAll("input, textarea").forEach(input => input.classList.remove("error")); +} + +form.addEventListener("submit", function(event) { + event.preventDefault(); // Prevent actual form submission + + clearErrors(); // Clear previous errors + + // Get values + const firstName = document.getElementById("first-name").value.trim(); + const lastName = document.getElementById("last-name").value.trim(); + const organization = document.getElementById("organization").value.trim(); + const email = document.getElementById("email").value.trim(); + const phone = document.getElementById("phone").value.trim(); const contactMethod = document.querySelector('input[name="contact-method"]:checked')?.value; - const message = document.getElementById('message').value.trim(); + const message = document.getElementById("message").value.trim(); - const errorMessages = []; + let hasErrors = false; - // First name validation + // First Name if (!firstName) { - errorMessages.push("Please enter your first name."); + showError("first-name", "Please enter your first name."); + hasErrors = true; } else if (firstName.length < 2) { - errorMessages.push("First name must be at least 2 characters."); + showError("first-name", "First name must be at least 2 characters."); + hasErrors = true; } - // Last name validation + // Last Name if (!lastName) { - errorMessages.push("Please enter your last name."); + showError("last-name", "Please enter your last name."); + hasErrors = true; } else if (lastName.length < 2) { - errorMessages.push("Last name must be at least 2 characters."); + showError("last-name", "Last name must be at least 2 characters."); + hasErrors = true; } - // Email validation + // Organization (optional) + if (organization.length > 0 && organization.length < 2) { + showError("organization", "Organization name must be at least 2 characters."); + hasErrors = true; + } + + // Email const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailPattern.test(email)) { - errorMessages.push("Please enter a valid email address."); + showError("email", "Please enter a valid email address."); + hasErrors = true; } - // Phone number validation (exactly 10 digits) - const phonePattern = /^\d{10}$/; + // Phone — match format: 123-456-7890 + const phonePattern = /^\d{3}-\d{3}-\d{4}$/; if (!phonePattern.test(phone)) { - errorMessages.push("Phone number must be exactly 10 digits (numbers only)."); + showError("phone", "Phone number must be in the format 123-456-7890."); + hasErrors = true; } - // Message validation + // Message if (message.length < 10) { - errorMessages.push("Message must be at least 10 characters long."); + showError("message", "Message must be at least 10 characters long."); + hasErrors = true; } - // Optional: Organization validation (only if provided) - if (organization.length > 0 && organization.length < 2) { - errorMessages.push("Organization name must be at least 2 characters if provided."); - } - - // Display errors or submit - const errorDiv = document.getElementById('errorMessages'); - if (errorMessages.length > 0) { - errorDiv.innerHTML = errorMessages.join("
"); - } else { - errorDiv.innerHTML = ""; + if (!hasErrors) { alert("Form submitted successfully!"); - // this.submit(); // Uncomment if actually submitting to a server + // form.submit(); // Uncomment when ready to send to server } }); -// This script isn't finished. +form.addEventListener("reset", function (event) { + const confirmed = confirm("Are you sure you want to clear the form?"); + if (!confirmed) { + event.preventDefault(); + return; + } + clearErrors(); +}); diff --git a/src/styles/about.css b/src/styles/about.css index 35ec16b..3d3f6b9 100644 --- a/src/styles/about.css +++ b/src/styles/about.css @@ -137,11 +137,26 @@ legend { } label { - display: block; + font-weight: 600; + font-size: 0.95rem; + color: #333; margin-bottom: 0.4rem; + display: block; font-weight: 500; } +.error-message { + color: red; + font-size: 0.9em; + margin-top: 4px; + display: block; +} + +input.error, textarea.error { + border-color: red; +} + + input[type="text"], input[type="email"], input[type="tel"], @@ -184,7 +199,13 @@ textarea:focus { } /* Button */ -button[type="submit"] { +.submit-reset { + display: flex; + gap: 20px; + justify-content: center; +} + +button[type="submit"], button[type="reset"] { margin:20px 0px 20px 0px; padding: 8px 25px; background-color: #ea7e0b; @@ -196,7 +217,7 @@ button[type="submit"] { transition: background-color 0.3s ease; } -button[type="submit"]:hover { +button[type="submit"]:hover, button[type="reset"]:hover { background-color: #2e97be; }