<!DOCTYPE html>
<html lang="en-GB">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Builders in Watford & London | R Craft Construction LTD</title>
<link rel="icon" href="favicon.svg" type="image/svg+xml">
<link rel="icon" href="favicon-32x32.png" type="image/png" sizes="32x32">
<link rel="icon" href="favicon.ico" sizes="16x16 32x32 48x48">
<link rel="apple-touch-icon" href="apple-touch-icon.png" sizes="180x180">
<meta name="theme-color" content="#1A1A14">
<link rel="canonical" href="https://rcraftconstruction.co.uk/">
<meta name="description" content="R Craft Construction LTD is a Watford-based builder serving London, Hertfordshire, Bedfordshire and nearby areas. Extensions, refurbishments, structural works and groundworks.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://rcraftconstruction.co.uk/">
<meta property="og:title" content="Builders in Watford & London | R Craft Construction LTD">
<meta property="og:description" content="R Craft Construction LTD is a Watford-based builder serving London, Hertfordshire, Bedfordshire and nearby areas. Extensions, refurbishments, structural works and groundworks.">
<meta property="og:image" content="https://rcraftconstruction.co.uk/rcraft-twitter.png">
<meta property="og:image:alt" content="R Craft Construction LTD social preview card">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Builders in Watford & London | R Craft Construction LTD">
<meta name="twitter:description" content="R Craft Construction LTD is a Watford-based builder serving London, Hertfordshire, Bedfordshire and nearby areas. Extensions, refurbishments, structural works and groundworks.">
<meta name="twitter:image" content="https://rcraftconstruction.co.uk/rcraft-twitter.png">
<meta name="twitter:image:alt" content="R Craft Construction LTD social preview card">
<meta property="og:locale" content="en_GB">
<meta property="og:site_name" content="R Craft Construction LTD">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@300;400;500;600&family=Barlow:wght@300;400;500;600&display=swap" rel="stylesheet">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "HomeAndConstructionBusiness",
"@id": "https://rcraftconstruction.co.uk/#business",
"url": "https://rcraftconstruction.co.uk/",
"logo": "https://rcraftconstruction.co.uk/rcraft_logo.png",
"image": "https://rcraftconstruction.co.uk/house-hero.png",
"name": "R Craft Construction LTD",
"description": "Watford-based construction company serving London, Hertfordshire, Bedfordshire and nearby areas with extensions, refurbishments, structural works and groundworks.",
"address": {
"@type": "PostalAddress",
"addressLocality": "Watford",
"addressCountry": "GB"
},
"areaServed": [
{
"@type": "Place",
"name": "Watford"
},
{
"@type": "Place",
"name": "Bushey"
},
{
"@type": "Place",
"name": "Northwood"
},
{
"@type": "Place",
"name": "Pinner"
},
{
"@type": "Place",
"name": "Harrow"
},
{
"@type": "Place",
"name": "St Albans"
},
{
"@type": "Place",
"name": "Hemel Hempstead"
},
{
"@type": "Place",
"name": "Borehamwood"
},
{
"@type": "Place",
"name": "Barnet"
},
{
"@type": "Place",
"name": "Edgware"
},
{
"@type": "Place",
"name": "Finchley"
},
{
"@type": "Place",
"name": "Wembley"
},
{
"@type": "Place",
"name": "Ealing"
},
{
"@type": "Place",
"name": "Brentford"
},
{
"@type": "Place",
"name": "Chiswick"
},
{
"@type": "Place",
"name": "Acton"
},
{
"@type": "Place",
"name": "Hammersmith"
},
{
"@type": "Place",
"name": "Battersea Park"
},
{
"@type": "Place",
"name": "Walthamstow"
},
{
"@type": "Place",
"name": "Camden"
},
{
"@type": "Place",
"name": "Islington"
},
{
"@type": "Place",
"name": "Richmond"
},
{
"@type": "Place",
"name": "Twickenham"
},
{
"@type": "Place",
"name": "Luton"
},
{
"@type": "Place",
"name": "Harston, Cambridgeshire"
}
],
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": [
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
],
"opens": "07:00",
"closes": "18:00"
}
],
"serviceType": [
"House extensions",
"Loft conversions",
"Property refurbishments",
"Structural works",
"Groundworks",
"Concrete works"
],
"sameAs": [
"https://instagram.com/rcraft.construction"
],
"telephone": "+447485133871",
"email": "[email protected]"
}
</script>
<link rel="stylesheet" href="assets/site.css?v=20260910">
</head>
<body>
<nav class="site-nav" aria-label="Main navigation">
<a href="#hero" class="nav-logo">
<img class="logo-image" src="rcraft_logo.png?v=3" width="866" height="288" alt="R Craft Construction LTD">
</a>
<button class="nav-toggle" type="button" aria-label="Open navigation" aria-controls="primary-navigation" aria-expanded="false">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</button>
<ul class="nav-links" id="primary-navigation">
<li><a href="#services">Services</a></li>
<li><a href="#about">About</a></li>
<li><a href="#projects">Portfolio</a></li>
<li><a href="#areas">Areas</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
<a href="tel:+447485133871" class="nav-cta">Call 07485 133871</a>
</nav>
<main id="main-content">
<section id="hero">
<div class="hero-slideshow" aria-hidden="true">
<img data-photo-slot="index-slide-1" class="hero-slide" src="gallery/02e421c1-e84b-41a4-b8b9-0576f0c745e7.jpg" width="1672" height="941" alt="Home exterior from the R Craft portfolio" fetchpriority="high" decoding="async">
<img data-photo-slot="index-slide-2" class="hero-slide" src="gallery/c960bdd3-5401-49e1-b31b-eb0f61296aa2.jpg" width="1672" height="941" alt="Building work in progress from the R Craft portfolio" decoding="async">
<img data-photo-slot="index-slide-3" class="hero-slide" src="gallery/71d8c4cb-7a3c-4990-a095-6a38c76465dd.jpg" width="1920" height="1080" alt="Roof construction from the R Craft portfolio" decoding="async">
<img data-photo-slot="index-slide-4" class="hero-slide hero-slide-level" src="gallery/229aafb3-0283-447c-9217-c83243cd29f5.jpg" width="1920" height="1080" alt="Spirit level during construction work" decoding="async">
<img data-photo-slot="index-slide-5" class="hero-slide" src="gallery/9f14128b-e670-4636-9054-fd65e113e9a8.jpg" width="1672" height="941" alt="Finished project from the R Craft portfolio" decoding="async">
</div>
<div class="hero-content">
<p class="hero-eyebrow">Craftsmanship matters.</p>
<h1>Building <em>Exceptional</em><br>Homes Across<br>Watford & London</h1>
<p class="hero-desc">Based in Watford, R Craft Construction specialises in house extensions, loft conversions, refurbishments, structural work and groundworks across London and the surrounding areas.</p>
<div class="hero-actions">
<a href="#contact" class="btn-primary">Discuss Your Project</a>
<a href="#projects" class="btn-ghost">View Portfolio</a>
</div>
</div>
<div class="hero-stats">
<div>
<div class="stat-num">200+</div>
<div class="stat-label">Projects Complete</div>
</div>
<div>
<div class="stat-num">10+</div>
<div class="stat-label">Years Experience</div>
</div>
<div>
<div class="stat-num">100%</div>
<div class="stat-label">Client Satisfaction</div>
</div>
</div>
</section>
<section id="services">
<div class="section-header">
<span class="section-eyebrow">What We Do</span>
<h2>Our Services</h2>
</div>
<div class="services-grid">
<div class="service-card" id="extensions-conversions">
<div class="service-icon">
<svg viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-width="1.5" xmlns="http://www.w3.org/2000/svg">
<rect x="6" y="24" width="36" height="18" rx="1"/>
<path d="M4 24l20-16 20 16"/>
<path d="M18 42V30h12v12"/>
<path d="M28 18h8v6"/>
</svg>
</div>
<h3 class="service-title">Extensions & Conversions</h3>
<div class="service-desc">Rear extensions, side returns, loft conversions and garage conversions to give your home the space it needs.</div>
<a class="text-link" href="extensions-and-conversions.html">Explore extensions & conversions <span aria-hidden="true">→</span></a>
</div>
<div class="service-card" id="refurbishments">
<div class="service-icon">
<svg viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-width="1.5" xmlns="http://www.w3.org/2000/svg">
<rect x="8" y="8" width="32" height="32" rx="2"/>
<path d="M8 20h32M20 8v32"/>
<circle cx="14" cy="14" r="2" fill="currentColor" stroke="none"/>
</svg>
</div>
<h3 class="service-title">Refurbishments</h3>
<div class="service-desc">Full and partial home refurbishments, including kitchens, bathrooms and work throughout the house, with a clear scope and agreed specification.</div>
<a class="text-link" href="property-refurbishments.html">Explore property refurbishments <span aria-hidden="true">→</span></a>
</div>
<div class="service-card" id="structural-works">
<div class="service-icon">
<svg viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-width="1.5" xmlns="http://www.w3.org/2000/svg">
<path d="M6 42V12l18-6 18 6v30"/>
<path d="M6 22h36M6 32h36"/>
<rect x="18" y="32" width="12" height="10"/>
</svg>
</div>
<h3 class="service-title">Structural Works & New Builds</h3>
<div class="service-desc">Structural alterations, new builds and underpinning, with the building work considered from the groundworks through to completion.</div>
<a class="text-link" href="structural-works.html">Explore structural works & new builds <span aria-hidden="true">→</span></a>
</div>
<div class="service-card" id="groundworks-concrete">
<div class="service-icon">
<svg viewBox="0 0 48 48" fill="none" stroke="currentColor" stroke-width="1.5" xmlns="http://www.w3.org/2000/svg">
<path d="M4 36h40M8 36V20l4-4h24l4 4v16"/>
<path d="M16 36V26h16v10"/>
<path d="M8 28h4M36 28h4"/>
</svg>
</div>
<h3 class="service-title">Groundworks & Concrete</h3>
<div class="service-desc">Foundations, retaining walls, drainage, driveways and concrete works for domestic building projects.</div>
<a class="text-link" href="groundworks-and-concrete.html">Explore groundworks & concrete <span aria-hidden="true">→</span></a>
</div>
</div>
</section>
<section id="about">
<div class="about-text">
<span class="section-eyebrow" style="display:block;margin-bottom:1rem;">Who We Are</span>
<h2 style="margin-bottom:1.5rem;">Watford-Based<br>Construction Experts</h2>
<div class="gold-line"></div>
<p class="about-body">R Craft Construction LTD is a Watford-based building contractor with over a decade of experience delivering high-quality domestic building and refurbishment projects across Watford, London, Hertfordshire, Bedfordshire, and surrounding areas. Our work ranges from individual rooms to extensions and wider structural alterations, with careful attention to the way the finished home will be used.</p>
<p class="about-body">We discuss the scope, specification and building programme with you before work begins, bringing the different stages of your project together through to handover.</p>
<ul class="about-list">
<li>Fully insured & accredited</li>
<li>Free detailed quotations</li>
<li>Project managed end-to-end</li>
<li>Serving Watford, London & surrounding areas</li>
<li>5-star rated by clients</li>
</ul>
</div>
<div class="about-visual">
<div class="about-box">
<p class="about-quote">“Good building work starts with understanding how you want to live in your home — and paying attention to the details that make it work.”</p>
</div>
</div>
</section>
<section id="projects">
<div class="section-header">
<span class="section-eyebrow">Portfolio</span>
<h2>Our Craftsmanship</h2>
</div>
<div class="projects-mosaic" data-portfolio-root><!-- PORTFOLIO_ITEMS -->
<div class="project-tile tall" data-portfolio-id="portfolio-floor" role="button" tabindex="0" aria-label="View full size image of Flooring & Rooflights">
<img class="tile-image" src="floor.png" alt="Finished floor with rooflights and black-framed doors" loading="lazy" decoding="async">
<div class="tile-content">
<div class="tile-tag">Flooring</div>
<div class="tile-title">Flooring & Rooflights</div>
</div>
</div>
<div class="project-tile" data-portfolio-id="portfolio-addition" role="button" tabindex="0" aria-label="View full size image of Timber-frame Extension">
<img class="tile-image" src="addition.png" alt="Timber-frame extension under construction against a brick property" loading="lazy" decoding="async">
<div class="tile-content">
<div class="tile-tag">Extension</div>
<div class="tile-title">Timber-frame Extension</div>
</div>
</div>
<div class="project-tile" data-portfolio-id="portfolio-extension" role="button" tabindex="0" aria-label="View full size image of Brickwork & Rooflights">
<img class="tile-image" src="gallery/41cc1974-a547-40f8-bd6c-1838b400353e.jpg" alt="Completed brick rear extension with flat roof and rooflights" loading="lazy" decoding="async">
<div class="tile-content">
<div class="tile-tag">Rear Extension</div>
<div class="tile-title">Brickwork & Rooflights</div>
</div>
</div>
<div class="project-tile" data-portfolio-id="portfolio-stairs" role="button" tabindex="0" aria-label="View full size image of Curved Stair Installation">
<img class="tile-image" src="stairs.png" alt="Curved timber stair installation during refurbishment" loading="lazy" decoding="async">
<div class="tile-content">
<div class="tile-tag">Bespoke Joinery</div>
<div class="tile-title">Curved Stair Installation</div>
</div>
</div>
<div class="project-tile" data-portfolio-id="portfolio-saw" role="button" tabindex="0" aria-label="View full size image of Site Carpentry">
<img class="tile-image" src="gallery/00d5895c-cbf1-4d00-9ec9-ee6d18275a91.jpg" alt="Carpenter cutting timber beams with a circular saw on site" loading="lazy" decoding="async">
<div class="tile-content">
<div class="tile-tag">Structural Works</div>
<div class="tile-title">Site Carpentry</div>
</div>
</div>
<!-- /PORTFOLIO_ITEMS --></div>
<div class="projects-cta">
<p style="font-size:0.85rem;color:var(--stone);margin-bottom:1.25rem;letter-spacing:0.05em;">See our full portfolio on Instagram</p>
<a href="https://instagram.com/rcraft.construction" class="btn-ghost" style="font-size:0.75rem;">@rcraft.construction</a>
</div>
</section>
<section id="areas">
<div class="section-header">
<span class="section-eyebrow">Where We Work</span>
<h2>Builders Serving Watford, London & Nearby Areas</h2>
</div>
<p class="areas-intro">Based in Watford, R Craft Construction works across local Hertfordshire towns, North and West London, selected South West and East London areas, Bedfordshire, and project locations further out by arrangement. Tell us your postcode and the work you have in mind so we can discuss your project and arrange the next steps.</p>
<div class="location-guides"><a href="builders-london.html"><span class="section-eyebrow">Building locally</span><h3>Builders in London</h3><p>Planning access, defining the scope and building across the capital.</p><span class="text-link">Explore London <span aria-hidden="true">→</span></span></a><a href="builders-watford.html"><span class="section-eyebrow">Building locally</span><h3>Builders in Watford</h3><p>Our home base, with practical advice for your Hertfordshire project.</p><span class="text-link">Explore Watford <span aria-hidden="true">→</span></span></a><a href="builders-harrow.html"><span class="section-eyebrow">Building locally</span><h3>Builders in Harrow</h3><p>Extensions, loft space and alterations to your existing home.</p><span class="text-link">Explore Harrow <span aria-hidden="true">→</span></span></a></div>
<div class="areas-grid">
<div class="area-card">
<h3 class="area-title">Watford & Hertfordshire</h3>
<ul class="area-list">
<li><a href="builders-watford.html">Watford</a></li>
<li>Bushey</li>
<li>Northwood</li>
<li>Pinner</li>
<li>Rickmansworth</li>
<li>St Albans</li>
<li>Hemel Hempstead</li>
<li>Borehamwood</li>
<li>Radlett</li>
</ul>
</div>
<div class="area-card">
<h3 class="area-title">London Service Areas</h3>
<ul class="area-list">
<li>Ealing</li>
<li>Brentford</li>
<li>Chiswick</li>
<li>Acton</li>
<li>Hammersmith</li>
<li>Battersea Park</li>
<li>Walthamstow</li>
<li><a href="builders-harrow.html">Harrow</a></li>
<li>Barnet</li>
<li>Edgware</li>
<li>Finchley</li>
<li>Wembley</li>
<li>Camden</li>
<li>Islington</li>
</ul>
</div>
<div class="area-card">
<h3 class="area-title">Wider Coverage</h3>
<ul class="area-list">
<li>Luton</li>
<li>Dunstable</li>
<li>Hitchin</li>
<li>Stevenage</li>
<li>Uxbridge</li>
<li>Enfield</li>
<li>Twickenham</li>
<li>Richmond</li>
<li>Harston</li>
<li>Cambridgeshire</li>
</ul>
</div>
</div>
</section>
<section id="contact">
<div class="contact-info">
<span class="section-eyebrow" style="display:block;margin-bottom:1rem;">Get in Touch</span>
<h2 style="margin-bottom:1.5rem;">Discuss Your Building Project</h2>
<div class="gold-line"></div>
<p class="contact-body">Ready to transform your property? We offer free, no-obligation quotations and site visits across Watford, London, Hertfordshire, Bedfordshire, and selected wider areas. Get in touch and we will respond within 24 hours.</p>
<div class="contact-detail">
<span class="contact-label">Call us</span>
<a class="btn-primary" href="tel:+447485133871">Call 07485 133871</a>
</div>
<div class="contact-detail">
<span class="contact-label">Email</span>
<a class="contact-value contact-email" href="mailto:[email protected]">[email protected]</a>
</div>
<div class="contact-detail">
<span class="contact-label">Location</span>
<span class="contact-value">Based in Watford<br>Serving Ealing, Brentford, Chiswick, Battersea Park, Walthamstow, Harrow, Barnet, Bushey, St Albans, Luton, Harston (Cambridgeshire), and nearby areas</span>
</div>
<div class="contact-detail">
<span class="contact-label">Instagram</span>
<span class="contact-value">@rcraft.construction</span>
</div>
<div class="contact-detail">
<span class="contact-label">Hours</span>
<span class="contact-value">Monday – Saturday<br>7:00am – 6:00pm</span>
</div>
</div>
<form class="contact-form" action="https://formspree.io/f/moeqrdkp" method="POST" enctype="multipart/form-data" onsubmit="handleSubmit(event)">
<div class="form-row">
<div class="form-group">
<label class="form-label" for="first-name">First Name</label>
<input id="first-name" name="first_name" autocomplete="given-name" required class="form-input" type="text" placeholder="John">
</div>
<div class="form-group">
<label class="form-label" for="surname">Surname</label>
<input id="surname" name="surname" autocomplete="family-name" class="form-input" type="text" placeholder="Smith">
</div>
</div>
<div class="form-group">
<label class="form-label" for="email">Email Address</label>
<input id="email" name="email" autocomplete="email" required class="form-input" type="email" placeholder="[email protected]">
</div>
<div class="form-group">
<label class="form-label" for="phone">Phone Number</label>
<input id="phone" name="phone" autocomplete="tel" class="form-input" type="tel" placeholder="+44 7XXX XXXXXX">
</div>
<div class="form-group">
<label class="form-label" for="service">Service Required</label>
<select id="service" name="service" class="form-select">
<option value="">Choose a service…</option>
<option>Extension or Loft Conversion</option>
<option>Refurbishment</option>
<option>Structural Works & New Builds</option>
<option>Groundworks & Concrete</option>
<option>Multiple Services</option>
<option>Other / Not Sure</option>
</select>
</div>
<div class="form-group">
<label class="form-label" for="message">Tell Us About Your Building Project</label>
<textarea id="message" name="message" required class="form-input" placeholder="Tell us about the work, your postcode and preferred timescale…"></textarea>
</div>
<div class="form-group photo-field">
<label class="form-label" for="project-photos">Project photos · Optional</label>
<input class="photo-input" id="project-photos" name="photos" type="file" accept="image/*" multiple aria-describedby="photos-help photos-status">
<label class="photo-picker" for="project-photos">
<span class="photo-picker-action">Add photos</span>
<span>One at a time or several together</span>
</label>
<p class="photo-help" id="photos-help">Show us the property or the area you would like to improve. Add up to 5 photos, with a maximum of 25 MB each and 90 MB in total. You can open the picker again to add more.</p>
<ul class="photo-list" id="photo-list" aria-label="Selected photos" hidden></ul>
<p class="photo-status" id="photos-status" aria-live="polite"></p>
</div>
<button type="submit" class="btn-primary" style="width:100%;padding:1.1rem;">Send Enquiry</button>
<p id="form-error" role="alert" tabindex="-1" hidden></p>
<div id="form-success" role="status" tabindex="-1" style="display:none;text-align:center;padding:1rem;color:var(--gold);font-size:0.85rem;letter-spacing:0.1em;text-transform:uppercase;">✓ Message sent — we will be in touch shortly</div>
</form>
</section>
</main>
<footer>
<div class="footer-top">
<div class="footer-brand">
<a href="#hero" class="footer-logo" aria-label="R Craft Construction LTD — back to top">
<img class="footer-logo-image" src="rcraft_logo.png?v=3" width="866" height="288" alt="R Craft Construction LTD" loading="lazy" decoding="async">
</a>
<p class="footer-summary">Craftsmanship matters. From the first foundations to the finishing details, we build and improve homes across Watford, London and the surrounding areas.</p>
<a href="#contact" class="btn-primary">Get a Quotation</a>
</div>
<div>
<h2 class="footer-heading">Our services</h2>
<ul class="footer-links">
<li><a href="extensions-and-conversions.html">Extensions & conversions</a></li>
<li><a href="property-refurbishments.html">Property refurbishments</a></li>
<li><a href="structural-works.html">Structural works & new builds</a></li>
<li><a href="groundworks-and-concrete.html">Concrete & groundworks</a></li>
</ul>
</div>
<div>
<h2 class="footer-heading">Explore</h2>
<ul class="footer-links">
<li><a href="#about">About R Craft</a></li>
<li><a href="#projects">Our project portfolio</a></li>
<li><a href="#areas">Areas we cover</a></li>
<li><a href="#contact">Request a free quotation</a></li>
</ul>
</div>
<div>
<h2 class="footer-heading">Get in touch</h2>
<a class="btn-primary footer-phone" href="tel:+447485133871">Call 07485 133871</a>
<a class="contact-email" href="mailto:[email protected]">[email protected]</a>
<p class="footer-summary">Based in Watford, Hertfordshire<br>Monday–Saturday<br>7:00am–6:00pm</p>
<a class="footer-social" href="https://instagram.com/rcraft.construction">Follow our work on Instagram ↗</a>
</div>
</div>
<div class="footer-coverage">
<span class="section-eyebrow">Built around you</span>
<p>Serving <a href="builders-watford.html">Watford</a>, Bushey, Northwood, <a href="builders-harrow.html">Harrow</a>, St Albans and homes across <a href="builders-london.html">London</a>, Hertfordshire and Bedfordshire. <a href="#areas">View our service areas</a>.</p>
</div>
<div class="footer-bottom">
<p class="footer-copy">© 2026 R Craft Construction LTD. All rights reserved.</p>
<a href="https://afterdarklabs.io">Website designed and hosted by After Dark Labs</a>
<a href="#hero">Back to top ↑</a>
</div>
</footer>
<div class="mobile-cta" inert aria-hidden="true">
<a href="tel:+447485133871" class="btn-primary">Call 07485 133871</a>
</div>
<div class="image-modal" id="image-modal" role="dialog" aria-modal="true" aria-hidden="true">
<button class="image-modal-close" type="button" aria-label="Close full screen image">×</button>
<img id="image-modal-img" src="" alt="">
</div>
<script src="assets/contact-photos.js"></script>
<script>
async function handleSubmit(e) {
e.preventDefault();
const form = e.target;
const submitButton = form.querySelector('button[type="submit"]');
if (submitButton.disabled || !form.reportValidity()) return;
const successMessage = document.getElementById('form-success');
const errorMessage = document.getElementById('form-error');
const data = new FormData(form);
contactPhotos.appendTo(data);
contactPhotos.setDisabled(true);
submitButton.disabled = true;
submitButton.textContent = 'Sending…';
form.setAttribute('aria-busy', 'true');
errorMessage.hidden = true;
try {
const response = await fetch(form.action, {
method: 'POST',
body: data,
headers: { Accept: 'application/json' }
});
if (!response.ok) {
const result = await response.json().catch(() => ({}));
const details = Array.isArray(result.errors)
? result.errors.map(error => error.message).filter(Boolean).join(' ')
: '';
const codes = Array.isArray(result.errors) ? result.errors.map(error => error.code) : [];
if (codes.includes('NO_FILE_UPLOADS')) {
throw new Error('Photos could not be accepted. Remove the photos and send your enquiry again, or email them to [email protected].');
}
if (response.status === 413 || codes.includes('FILES_TOO_BIG')) {
throw new Error('The photo upload is too large. Please choose smaller photos and try again.');
}
throw new Error(response.status === 429
? 'Too many enquiries have been sent. Please wait a few minutes and try again, or call 07485 133871.'
: details || 'Your enquiry could not be sent. Please try again, or call 07485 133871.');
}
form.reset();
contactPhotos.clear();
form.classList.add('is-submitted');
successMessage.style.display = 'block';
successMessage.focus();
} catch (error) {
errorMessage.textContent = error instanceof TypeError
? 'We could not connect to send your enquiry. Please check your connection and try again, or call 07485 133871.'
: error.message;
errorMessage.hidden = false;
errorMessage.focus();
} finally {
form.removeAttribute('aria-busy');
contactPhotos.setDisabled(false);
submitButton.disabled = false;
submitButton.textContent = 'Send Enquiry';
}
}
const siteNav = document.querySelector('nav');
const mobileCta = document.querySelector('.mobile-cta');
const hero = document.getElementById('hero');
const mobileViewport = window.matchMedia('(max-width: 600px)');
const navToggle = document.querySelector('.nav-toggle');
const navSectionLinks = Array.from(document.querySelectorAll('.nav-links a[href^="#"]'));
const navSections = navSectionLinks
.map((link) => ({ link, section: document.querySelector(link.getAttribute('href')) }))
.filter(({ section }) => section);
function setMobileNav(open) {
siteNav.classList.toggle('is-open', open);
navToggle.setAttribute('aria-expanded', String(open));
navToggle.setAttribute('aria-label', open ? 'Close navigation' : 'Open navigation');
}
function setActiveNavLink(activeId) {
navSections.forEach(({ link, section }) => {
const isActive = section.id === activeId;
link.classList.toggle('is-active', isActive);
if (isActive) {
link.setAttribute('aria-current', 'location');
} else {
link.removeAttribute('aria-current');
}
});
}
function updateActiveNavLink() {
const showMobileCta = mobileViewport.matches && hero.getBoundingClientRect().bottom <= 0;
mobileCta.classList.toggle('is-visible', showMobileCta);
mobileCta.inert = !showMobileCta;
mobileCta.setAttribute('aria-hidden', String(!showMobileCta));
const navOffset = siteNav.offsetHeight + 24;
let activeId = '';
navSections.forEach(({ section }) => {
if (section.getBoundingClientRect().top <= navOffset) {
activeId = section.id;
}
});
setActiveNavLink(activeId);
}
navToggle.addEventListener('click', () => {
setMobileNav(!siteNav.classList.contains('is-open'));
});
document.querySelectorAll('.nav-links a, .nav-cta, .mobile-cta a').forEach((link) => {
link.addEventListener('click', () => {
const href = link.getAttribute('href');
const targetId = href?.startsWith('#') ? href.slice(1) : null;
if (targetId) {
setActiveNavLink(targetId);
}
setMobileNav(false);
});
});
window.addEventListener('scroll', updateActiveNavLink, { passive: true });
window.addEventListener('resize', updateActiveNavLink);
window.addEventListener('load', updateActiveNavLink);
updateActiveNavLink();
// On phones, skip the contact details and land directly at the enquiry form.
function scrollToMobileContactForm() {
if (!mobileViewport.matches) return;
setMobileNav(false);
const form = document.querySelector('.contact-form');
const top = window.scrollY + form.getBoundingClientRect().top - siteNav.offsetHeight - 16;
window.scrollTo({
top,
behavior: window.matchMedia('(prefers-reduced-motion: reduce)').matches ? 'instant' : 'smooth'
});
}
document.querySelectorAll('a[href="#contact"]').forEach((link) => {
link.addEventListener('click', (event) => {
if (!mobileViewport.matches || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) return;
event.preventDefault();
if (window.location.hash !== '#contact') history.pushState(null, '', '#contact');
scrollToMobileContactForm();
});
});
// Also handle contact links arriving from service and location pages.
window.addEventListener('load', () => {
if (window.location.hash === '#contact') scrollToMobileContactForm();
});
window.addEventListener('hashchange', () => {
if (window.location.hash === '#contact') scrollToMobileContactForm();
});
const modal = document.getElementById('image-modal');
const modalImage = document.getElementById('image-modal-img');
const closeModalButton = modal.querySelector('.image-modal-close');
let lastFocusedElement = null;
function openImageModal(image) {
lastFocusedElement = document.activeElement;
modalImage.src = image.currentSrc || image.src;
modalImage.alt = image.alt;
modal.classList.add('is-open');
modal.setAttribute('aria-hidden', 'false');
document.body.classList.add('modal-open');
closeModalButton.focus();
}
function closeImageModal() {
modal.classList.remove('is-open');
modal.setAttribute('aria-hidden', 'true');
document.body.classList.remove('modal-open');
modalImage.removeAttribute('src');
modalImage.alt = '';
if (lastFocusedElement) {
lastFocusedElement.focus();
}
}
document.querySelectorAll('.project-tile').forEach((tile) => {
tile.addEventListener('click', () => {
openImageModal(tile.querySelector('.tile-image'));
});
tile.addEventListener('keydown', (event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
openImageModal(tile.querySelector('.tile-image'));
}
});
});
closeModalButton.addEventListener('click', closeImageModal);
modal.addEventListener('click', (event) => {
if (event.target === modal) {
closeImageModal();
}
});
document.addEventListener('keydown', (event) => {
if (event.key !== 'Escape') {
return;
}
if (modal.classList.contains('is-open')) {
closeImageModal();
}
if (siteNav.classList.contains('is-open')) {
setMobileNav(false);
navToggle.focus();
}
});
</script>
</body>
</html>