import { useEffect } from 'react' import { useLocation } from 'react-router-dom' export default function ScrollToTop() { const { pathname, hash } = useLocation() // Cross-page navigation: scroll to hash or top on route change. // // getElementById, not querySelector. querySelector THROWS on a fragment that // is not a valid CSS selector, and an id starting with a digit is not one: // `#8x8-implementation` and even `/#1` would throw here, in an effect inside // the root route, and the error boundary would replace the header, the page // and the footer with the error screen. The long-form service pages exist to // be deep-linked from search results and AI answers, so a link nobody here // wrote must never be able to blank the page. An unknown id scrolls to top. useEffect(() => { if (hash.length > 1) { let el = null try { el = document.getElementById(decodeURIComponent(hash.slice(1))) } catch { el = null // a fragment that is not valid percent-encoding } if (el) { el.scrollIntoView({ behavior: 'smooth' }) return } } window.scrollTo(0, 0) }, [pathname, hash]) // Same-page: React Router won't re-navigate if URL is already identical, // so intercept clicks on any link pointing to #contact-form directly. useEffect(() => { const handleClick = (e) => { const anchor = e.target.closest('a') if (!anchor) return const href = anchor.getAttribute('href') || '' if (!href.includes('#contact-form')) return const el = document.querySelector('#contact-form') if (!el) return e.preventDefault() el.scrollIntoView({ behavior: 'smooth' }) window.history.pushState(null, '', '#contact-form') } document.addEventListener('click', handleClick) return () => document.removeEventListener('click', handleClick) }, []) return null }