Skip to content
mroot.co
← All writing
Case StudiesJul 17, 2026 · 1 min read

Replacing the photographer contact form with a funnel that quotes itself

A demo photography portfolio where the contact page is a four-step inquiry funnel — shoot type, date, location, contact — validated per step so every inquiry arrives quotable.

Project: North Creekopen →

North Creek Photography is a demo build — a fictional wedding, family, and brand photographer in Ann Arbor. Photographer sites are usually a beautiful portfolio with a bare contact form at the end, which means the first client email always triggers a round of "what kind of shoot? when? where?" before a quote can happen.

Stack: React 19, TypeScript, Vite, Tailwind CSS v4, with motion for the funnel transitions. Static deploy on a Cloudflare Worker. The visual language is image-first: a warm paper background, Cormorant Garamond serifs, and a filterable masonry grid of twelve shots with a lightbox.

The funnel collects what a quote needs

The inquiry funnel walks through four steps — shoot type, date, location, contact details — and won't advance until the current step is actually usable:

src/components/InquiryFunnel.tsx
const isStepValid = () => {  switch (step) {    case 1:      return formData.shootType !== '';    case 2:      return isFlexibleDate || formData.date !== '';    case 3:      return formData.location.trim().length > 2;    case 4:      return (        formData.name.trim().length > 1 &&        /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email) &&        formData.phone.trim().length > 6      );    default:      return false;  }};

Small touches matter here: date has an "I'm flexible" escape hatch so an unset date doesn't block a real lead, and clicking a package on the pricing section opens the funnel with the shoot type pre-selected — the highest-intent visitors skip a step.

Pricing is published

Three packages with real price labels, plus an FAQ. Same reasoning as everywhere else in this demo series: hiding prices doesn't filter anyone worth filtering.

What I'd improve

  • Submissions render a confirmation but don't deliver anywhere; a Worker endpoint with email notification is the missing piece.
  • The masonry grid loads all twelve images eagerly — fine at this size, but it should lazy-load before a real client's 200-photo portfolio goes in.

One of eight small-business demos on this site. Projects · Get a quote

Marc Delacruz — full-stack, security-minded.Get in touch →