Spray Paint Quote Request

Request a spray paint quote

Fill in the details below and we’ll get back to you with a price.

Enter your name.
Enter your phone number.
Enter a valid email address.
Enter your vehicle make and model.
Enter your car colour.
⚠ Please zoom out when taking photos — we need to see the full panel and surrounding area so we can zoom in on our end.
📸 Can’t upload photos right now? No problem — submit the form and email your photos to us separately at [email protected] with your name in the subject line.
Upload at least one photo, or submit and email them to us separately.

Tick everything that applies to the panel(s) to be painted

Select at least one panel condition.

Does it need us to remove and refit any trims or parts?

Let us know if remove and refit is needed.

Choose the option that best matches what you’re after

Select your expected finish.
Something went wrong sending your request. Please call us directly or try again.

Quote request sent!

Thanks — we’ve received your details and will be in touch soon with a price.
If you haven’t uploaded photos yet, please email them to [email protected]

action=”https://formspree.io/f/mgojzvvp” const fileInput = document.getElementById(‘vphoto’); const preview = document.getElementById(‘preview’); fileInput.addEventListener(‘change’, () => { preview.innerHTML = ”; Array.from(fileInput.files).slice(0, 12).forEach(f => { const img = document.createElement(‘img’); img.src = URL.createObjectURL(f); img.className = ‘preview-thumb’; preview.appendChild(img); }); }); function onJobChange() { const val = document.querySelector(‘input[name=”jobtype”]:checked’); const guide = document.getElementById(‘angleGuide’); const isFullJob = val && ( val.value.includes(‘inside and out’) || val.value.includes(‘outside only’) ); guide.style.display = isFullJob ? ‘block’ : ‘none’; } document.getElementById(‘condOtherCheck’).addEventListener(‘change’, function () { document.getElementById(‘condOtherText’).style.display = this.checked ? ‘block’ : ‘none’; }); const ecMap = { ec1: ‘ec1’, ec2: ‘ec2’, ec3: ‘ec3’, ec4: ‘ec4’, ec5: ‘ec5’, ec6: ‘ec6’ }; function selectExpect() { [‘ec1′,’ec2′,’ec3′,’ec4′,’ec5′,’ec6’].forEach(id => document.getElementById(id).classList.remove(‘selected’)); const checked = document.querySelector(‘input[name=”expectation”]:checked’); if (!checked) return; const card = checked.closest(‘.expect-card’); if (card) card.classList.add(‘selected’); document.getElementById(‘expOtherText’).style.display = checked.value === ‘other_expect’ ? ‘block’ : ‘none’; } function showErr(id, show) { document.getElementById(id).style.display = show ? ‘block’ : ‘none’; } function fieldErr(fieldId, show) { const el = document.getElementById(fieldId); if (show) el.classList.add(‘field-error’); else el.classList.remove(‘field-error’); } function sectionErr(sectionId, show) { const el = document.getElementById(sectionId); if (show) el.classList.add(‘section-error’); else el.classList.remove(‘section-error’); } async function handleSubmit() { const name = document.getElementById(‘custName’).value.trim(); const phone = document.getElementById(‘custPhone’).value.trim(); const email = document.getElementById(‘custEmail’).value.trim(); const model = document.getElementById(‘vmodel’).value.trim(); const colour = document.getElementById(‘vcolour’).value.trim(); const jobtype = document.querySelector(‘input[name=”jobtype”]:checked’); const partName = document.getElementById(‘partName’).value.trim(); const photos = fileInput.files.length; const conditions = document.querySelectorAll(‘input[name=”condition”]:checked’); const rnr = document.querySelector(‘input[name=”rnr”]:checked’); const expectation = document.querySelector(‘input[name=”expectation”]:checked’); const emailRx = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; fieldErr(‘f-name’, !name); showErr(‘err-name’, !name); fieldErr(‘f-phone’, !phone); showErr(‘err-phone’, !phone); fieldErr(‘f-email’, !email || !emailRx.test(email)); showErr(‘err-email’, !email || !emailRx.test(email)); fieldErr(‘f-model’, !model); showErr(‘err-model’, !model); fieldErr(‘f-colour’, !colour); showErr(‘err-colour’, !colour); const jobtypeErr = !jobtype || (jobtype.value === ‘one_part’ && !partName); sectionErr(‘s-jobtype’, jobtypeErr); showErr(‘err-jobtype’, jobtypeErr); const condErr = conditions.length === 0; sectionErr(‘s-condition’, condErr); showErr(‘err-condition’, condErr); const rnrErr = !rnr; sectionErr(‘s-rnr’, rnrErr); showErr(‘err-rnr’, rnrErr); const expectErr = !expectation; sectionErr(‘s-expect’, expectErr); showErr(‘err-expect’, expectErr); const hasErrors = !name || !phone || !email || !emailRx.test(email) || !model || !colour || jobtypeErr || condErr || rnrErr || expectErr; if (hasErrors) { const firstErr = document.querySelector(‘.field-error, .section-error’); if (firstErr) firstErr.scrollIntoView({ behavior: ‘smooth’, block: ‘center’ }); return; } /* Build job type string */ let jobtypeStr = jobtype.value; if (jobtype.value === ‘one_part’) jobtypeStr = ‘One part only: ‘ + partName; /* Build conditions string */ const condList = Array.from(conditions).map(c => { if (c.value === ‘Other’) { const extra = document.getElementById(‘condOtherText’).value.trim(); return extra ? ‘Other: ‘ + extra : ‘Other’; } return c.value; }).join(‘, ‘); /* Build expectation string */ let expectStr = expectation.value; if (expectation.value === ‘other_expect’) { expectStr = ‘Other: ‘ + (document.getElementById(‘expOtherText’).value.trim() || ‘(no details given)’); } /* Disable button while sending */ const btn = document.getElementById(‘submitBtn’); btn.disabled = true; btn.innerHTML = ‘ Sending…’; document.getElementById(‘submitError’).style.display = ‘none’; try { const fd = new FormData(); fd.append(‘name’, name); fd.append(‘phone’, phone); fd.append(’email’, email); fd.append(‘vehicle’, model + ‘ — ‘ + colour); fd.append(‘job_type’, jobtypeStr); fd.append(‘photos_uploaded’, photos > 0 ? photos + ‘ photo(s) uploaded’ : ‘No photos uploaded — customer to email separately’); fd.append(‘panel_condition’, condList); fd.append(‘remove_refit’, rnr.value); fd.append(‘expectation’, expectStr); fd.append(‘_subject’, ‘New spray paint quote request — ‘ + name); /* Attach photos if any */ Array.from(fileInput.files).forEach((f, i) => { fd.append(‘photo_’ + (i + 1), f); }); const res = await fetch(FORMSPREE_URL, { method: ‘POST’, body: fd, headers: { ‘Accept’: ‘application/json’ } }); if (res.ok) const formData = new FormData(); formData.append(‘name’, name); formData.append(‘phone’, phone); formData.append(’email’, email); formData.append(‘vehicle’, model + ‘ — ‘ + colour); formData.append(‘job_type’, document.querySelector(‘input[name=”jobtype”]:checked’).value); formData.append(‘condition’, Array.from(conditions).map(c => c.value).join(‘, ‘)); formData.append(‘remove_refit’, rnr.value); formData.append(‘expectation’, expectation.value); fetch(‘https://formspree.io/f/xxxxxxxx’, { method: ‘POST’, body: formData, headers: { ‘Accept’: ‘application/json’ } }).then(r => { if (r.ok) { document.getElementById(‘theForm’).style.display = ‘none’; document.getElementById(‘successScreen’).style.display = ‘block’; window.scrollTo({ top: 0, behavior: ‘smooth’ }); } else { alert(‘Something went wrong. Please call us directly.’); } }); } else { throw new Error(‘Server error’); } } catch (e) { document.getElementById(‘submitError’).style.display = ‘block’; btn.disabled = false; btn.innerHTML = ‘ Submit quote request’; } }