From ac2d64caafcbaa088c5c8e62831772c416e3dfc8 Mon Sep 17 00:00:00 2001 From: Tudor Sitaru Date: Tue, 14 Apr 2026 21:02:18 +0100 Subject: [PATCH] feat(home): implement redesigned homepage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Hero: Playfair heading with coral italic accent, teal eyebrow pill, richer sub-copy describing both primary and secondary coverage - Discovery: geolocation "Schools near me" button (reverse-geocodes via postcodes.io → /?postcode=…&radius=1), plus Start exploring chips linking to /rankings and /compare - How it works: 3-card grid showing miniature real-UI previews for Performance (primary SATs cascade + secondary Att8 bar), Ofsted inspection card, and side-by-side Compare table - Editorial: text column + factbox (totalSchools, LA count, coverage dates) rendered inside a white card below the how-it-works section - Footer: expanded to 3 columns (brand blurb, Product, Resources); links updated to / /rankings /compare and real gov.uk/ofsted URLs - All new sections visible only on landing (no search active) Co-Authored-By: Claude Opus 4.6 --- nextjs-app/components/Footer.module.css | 4 +- nextjs-app/components/Footer.tsx | 31 +- nextjs-app/components/HomeView.module.css | 674 +++++++++++++++++++++- nextjs-app/components/HomeView.tsx | 268 ++++++++- 4 files changed, 930 insertions(+), 47 deletions(-) diff --git a/nextjs-app/components/Footer.module.css b/nextjs-app/components/Footer.module.css index 2386e91..2843146 100644 --- a/nextjs-app/components/Footer.module.css +++ b/nextjs-app/components/Footer.module.css @@ -12,8 +12,8 @@ .content { display: grid; - grid-template-columns: 2fr 1fr; - gap: 3rem; + grid-template-columns: 1.5fr 1fr 1fr; + gap: 2rem; margin-bottom: 3rem; } diff --git a/nextjs-app/components/Footer.tsx b/nextjs-app/components/Footer.tsx index 54d1bac..c327bf2 100644 --- a/nextjs-app/components/Footer.tsx +++ b/nextjs-app/components/Footer.tsx @@ -15,23 +15,22 @@ export function Footer() {

SchoolCompare

- Compare primary and secondary schools across England. + Compare primary and secondary schools across England. Free, independent, built on public data.

+
+

Product

+ +
+

Resources

diff --git a/nextjs-app/components/HomeView.module.css b/nextjs-app/components/HomeView.module.css index ecaaebf..05503a5 100644 --- a/nextjs-app/components/HomeView.module.css +++ b/nextjs-app/components/HomeView.module.css @@ -4,32 +4,73 @@ .heroSection { text-align: center; - margin-bottom: 2rem; - padding-top: 1rem; + margin-bottom: 1.5rem; + padding-top: 2.5rem; +} + +.heroEyebrow { + display: inline-flex; + align-items: center; + gap: 0.4rem; + font-size: 0.72rem; + font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--accent-teal, #2d7d7d); + background: rgba(45, 125, 125, 0.1); + padding: 0.3rem 0.7rem; + border-radius: 999px; + margin-bottom: 1rem; +} + +.heroEyebrowDot { + display: inline-block; + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--accent-teal, #2d7d7d); } .heroTitle { - font-size: 2.5rem; + font-size: 3rem; font-weight: 700; color: var(--text-primary, #1a1612); - margin-bottom: 0.5rem; - line-height: 1.2; + margin-bottom: 0.85rem; + line-height: 1.08; + letter-spacing: -0.015em; font-family: var(--font-playfair), 'Playfair Display', serif; + max-width: 840px; + margin-left: auto; + margin-right: auto; +} + +.heroEmph { + color: var(--accent-coral-dark, #c45a3f); + font-style: italic; } .heroDescription { - font-size: 1.1rem; + font-size: 1.05rem; color: var(--text-secondary, #5c564d); - margin: 0 auto; - max-width: 600px; + margin: 0 auto 0.5rem; + max-width: 680px; + line-height: 1.55; +} + +.heroDescription strong { + color: var(--text-primary, #1a1612); + font-weight: 700; } @media (max-width: 768px) { + .heroSection { + padding-top: 1.5rem; + } .heroTitle { - font-size: 1.75rem; + font-size: 2rem; } .heroDescription { - font-size: 1rem; + font-size: 0.95rem; } } @@ -423,26 +464,67 @@ } .discoverySection { - padding: 2rem var(--page-padding, 2rem); + padding: 0.5rem 0 0.5rem; text-align: center; } -.discoveryCount { - font-size: 1.1rem; - color: var(--text-secondary); - margin-bottom: 0.5rem; -} - -.discoveryCount strong { - color: var(--text-primary); - font-size: 1.25rem; -} - -.discoveryHints { - color: var(--text-muted); +.nearMeRow { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5rem; margin-bottom: 1.25rem; } +.nearMeBtn { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.625rem 1.375rem; + background: var(--accent-teal, #2d7d7d); + color: #fff; + border: none; + border-radius: 999px; + font-size: 0.9375rem; + font-weight: 600; + cursor: pointer; + transition: background 0.2s ease, transform 0.15s ease; + font-family: inherit; +} + +.nearMeBtn:hover:not(:disabled) { + background: #235f5f; + transform: translateY(-1px); +} + +.nearMeBtn:disabled { + opacity: 0.7; + cursor: not-allowed; +} + +.nearMeBtnSpinner { + display: inline-block; + width: 14px; + height: 14px; + border: 2px solid rgba(255, 255, 255, 0.35); + border-top-color: #fff; + border-radius: 50%; + animation: nearMeSpin 0.7s linear infinite; + flex-shrink: 0; +} + +@keyframes nearMeSpin { + to { transform: rotate(360deg); } +} + +.geoError { + font-size: 0.8125rem; + color: var(--accent-coral, #e07256); + margin: 0; + max-width: 340px; + text-align: center; +} + .quickSearches { display: flex; align-items: center; @@ -473,6 +555,550 @@ border-color: var(--accent-coral); } +.exploringRow { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.6rem; + margin-top: 1rem; +} + +.exploringLabel { + font-size: 0.72rem; + color: var(--text-muted, #6d685f); + font-weight: 500; + letter-spacing: 0.04em; + text-transform: uppercase; +} + +.exploringChips { + display: flex; + gap: 0.5rem; + justify-content: center; + flex-wrap: wrap; +} + +.exploringChip { + display: inline-flex; + align-items: center; + gap: 0.4rem; + padding: 0.5rem 0.95rem; + background: var(--bg-card, white); + border: 1px solid var(--border-color, #e5dfd5); + border-radius: 999px; + font-size: 0.82rem; + font-weight: 500; + color: var(--text-secondary, #5c564d); + text-decoration: none; + transition: all 0.15s ease; +} + +.exploringChip:hover { + border-color: var(--accent-coral, #e07256); + color: var(--accent-coral-dark, #c45a3f); + transform: translateY(-1px); +} + +.chipDot { + display: inline-block; + width: 6px; + height: 6px; + border-radius: 50%; + background: currentColor; + opacity: 0.55; + flex-shrink: 0; +} + +/* ── How it works section ─────────────────────────────── */ + +.howItWorks { + padding: 3rem 0 1rem; +} + +.hiwHeader { + display: flex; + align-items: baseline; + justify-content: space-between; + flex-wrap: wrap; + gap: 0.5rem; + margin-bottom: 1.5rem; +} + +.hiwHeading { + font-family: var(--font-playfair), 'Playfair Display', serif; + font-size: 1.75rem; + font-weight: 700; + color: var(--text-primary, #1a1612); + margin: 0; +} + +.hiwSub { + font-size: 0.875rem; + color: var(--text-muted, #6d685f); +} + +.hiwGrid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1rem; +} + +.hiwCard { + background: var(--bg-card, white); + border: 1px solid var(--border-color, #e5dfd5); + border-radius: 14px; + padding: 1.25rem; + box-shadow: 0 2px 8px rgba(26, 22, 18, 0.06); + display: flex; + flex-direction: column; + gap: 0.9rem; +} + +.hiwVisual { + background: var(--bg-secondary, #f3ede4); + border-radius: 10px; + padding: 0.9rem; + min-height: 180px; + display: flex; + flex-direction: column; + justify-content: center; + gap: 0.75rem; +} + +.hiwPhaseBlock { + display: flex; + flex-direction: column; + gap: 0.35rem; +} + +.hiwPhaseLabel { + font-size: 0.58rem; + font-weight: 600; + letter-spacing: 0.1em; + text-transform: uppercase; + color: var(--text-muted, #6d685f); +} + +.hiwPhaseLabel strong { + color: var(--accent-teal, #2d7d7d); + font-weight: 700; +} + +.hiwCardBody { + display: flex; + flex-direction: column; + gap: 0.3rem; +} + +.hiwStep { + font-size: 0.65rem; + font-weight: 700; + letter-spacing: 0.1em; + text-transform: uppercase; + color: var(--accent-coral, #e07256); +} + +.hiwTitle { + font-family: var(--font-playfair), 'Playfair Display', serif; + font-size: 1.1rem; + font-weight: 700; + color: var(--text-primary, #1a1612); + line-height: 1.25; +} + +.hiwDesc { + font-size: 0.86rem; + color: var(--text-secondary, #5c564d); + line-height: 1.45; + margin: 0; +} + +/* Mini cascade (performance card) */ +.miniCascade { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 0.4rem; +} + +.miniCascadeCol { + display: flex; + flex-direction: column; + gap: 0.15rem; + min-width: 0; +} + +.miniSubj { + font-size: 0.5rem; + font-weight: 700; + letter-spacing: 0.1em; + text-transform: uppercase; + color: var(--text-muted, #6d685f); + margin-bottom: 0.1rem; +} + +.miniRowHead { + display: flex; + justify-content: space-between; + font-size: 0.48rem; + color: var(--text-muted, #6d685f); + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.miniRowHead strong { + font-family: var(--font-playfair), 'Playfair Display', serif; + font-size: 0.62rem; + color: var(--text-primary, #1a1612); + font-weight: 700; + letter-spacing: 0; + text-transform: none; +} + +.miniTrack { + height: 5px; + border-radius: 2px; + background: rgba(45, 125, 125, 0.08); + position: relative; + overflow: visible; +} + +.miniBarExp { + height: 100%; + border-radius: 2px; + background: var(--accent-teal-light, #3a9e9e); +} + +.miniBarExc { + height: 100%; + border-radius: 2px; + background: var(--accent-teal, #2d7d7d); +} + +.miniNatPill { + position: absolute; + top: -9px; + transform: translateX(-50%); + background: var(--accent-coral, #e07256); + color: #fff; + font-size: 0.4rem; + font-weight: 700; + padding: 0.05rem 0.2rem; + border-radius: 3px; + z-index: 2; + white-space: nowrap; + pointer-events: none; +} + +/* Attainment 8 mini bar */ +.att8Row { + display: grid; + grid-template-columns: 1fr auto; + gap: 0.6rem; + align-items: center; +} + +.att8BarWrap { + display: flex; + flex-direction: column; + gap: 0.2rem; +} + +.att8BarHead { + display: flex; + justify-content: space-between; + font-size: 0.5rem; + color: var(--text-muted, #6d685f); + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.att8Track { + height: 7px; + background: rgba(45, 125, 125, 0.08); + border-radius: 3px; + position: relative; +} + +.att8Fill { + height: 100%; + background: var(--accent-teal, #2d7d7d); + border-radius: 3px; +} + +.att8NatLine { + position: absolute; + top: -2px; + bottom: -2px; + width: 1.5px; + background: rgba(224, 114, 86, 0.6); + z-index: 2; +} + +.att8Score { + text-align: right; +} + +.att8Value { + font-family: var(--font-playfair), 'Playfair Display', serif; + font-size: 1.5rem; + font-weight: 700; + color: var(--accent-teal, #2d7d7d); + line-height: 1; +} + +.att8Delta { + font-size: 0.55rem; + color: var(--accent-teal, #2d7d7d); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.04em; + margin-top: 0.15rem; +} + +/* Ofsted preview */ +.ofstedPreview { + display: flex; + flex-direction: column; + gap: 0.5rem; + width: 100%; + padding: 0.4rem 0.2rem; +} + +.ofstedHead { + display: flex; + align-items: center; + gap: 0.5rem; + padding-bottom: 0.4rem; + border-bottom: 1.5px solid var(--border-color, #e5dfd5); +} + +.ofstedBullet { + display: block; + width: 3px; + height: 1em; + background: var(--accent-coral, #e07256); + border-radius: 2px; + flex-shrink: 0; +} + +.ofstedTitle { + font-family: var(--font-playfair), 'Playfair Display', serif; + font-size: 0.85rem; + font-weight: 600; + color: var(--text-primary, #1a1612); +} + +.ofstedBadge { + align-self: flex-start; + padding: 0.2rem 0.55rem; + border-radius: 4px; + background: rgba(45, 125, 125, 0.12); + color: var(--accent-teal, #2d7d7d); + font-size: 0.55rem; + font-weight: 700; + letter-spacing: 0.05em; +} + +.ofstedVerdict { + font-family: var(--font-playfair), 'Playfair Display', serif; + font-size: 1.05rem; + font-weight: 700; + line-height: 1.2; + color: var(--text-primary, #1a1612); +} + +.ofstedVerdict em { + color: var(--accent-teal, #2d7d7d); + font-style: normal; +} + +.ofstedMeta { + font-size: 0.6rem; + color: var(--text-muted, #6d685f); +} + +/* Compare preview */ +.comparePreview { + width: 100%; + background: var(--bg-card, white); + border: 1px solid var(--border-color, #e5dfd5); + border-radius: 8px; + overflow: hidden; + font-size: 0.6rem; +} + +.compareHead { + display: grid; + grid-template-columns: 1fr repeat(2, 1fr); + background: rgba(45, 125, 125, 0.1); + padding: 0.35rem 0.5rem; + gap: 0.35rem; +} + +.compareHeadCell { + font-family: var(--font-playfair), 'Playfair Display', serif; + font-size: 0.62rem; + font-weight: 700; + color: var(--accent-teal, #2d7d7d); + line-height: 1.2; +} + +.compareHeadLabel { + font-family: inherit; + font-size: 0.48rem; + color: var(--text-muted, #6d685f); + font-weight: 500; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.compareRow { + display: grid; + grid-template-columns: 1fr repeat(2, 1fr); + padding: 0.3rem 0.5rem; + gap: 0.35rem; + border-top: 1px solid var(--border-color, #e5dfd5); + align-items: baseline; +} + +.compareRowLabel { + font-size: 0.55rem; + color: var(--text-muted, #6d685f); + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.compareRowVal { + font-family: var(--font-playfair), 'Playfair Display', serif; + font-size: 0.72rem; + font-weight: 700; + color: var(--text-primary, #1a1612); +} + +.compareRowValHi { + color: var(--accent-teal, #2d7d7d); +} + +.compareFoot { + font-size: 0.52rem; + color: var(--text-muted, #6d685f); + padding: 0.35rem 0.5rem; + background: var(--bg-secondary, #f3ede4); + text-transform: uppercase; + letter-spacing: 0.06em; + text-align: center; + border-top: 1px solid var(--border-color, #e5dfd5); +} + +@media (max-width: 768px) { + .hiwGrid { + grid-template-columns: 1fr; + } + .hiwHeader { + flex-direction: column; + align-items: flex-start; + } + .hiwHeading { + font-size: 1.4rem; + } +} + +/* ── Editorial section ───────────────────────────────── */ + +.editorial { + padding: 2rem 0 3rem; +} + +.editorialGrid { + display: grid; + grid-template-columns: 1.4fr 1fr; + gap: 2rem; + padding: 1.75rem; + background: var(--bg-card, white); + border: 1px solid var(--border-color, #e5dfd5); + border-radius: 14px; +} + +.editorialText { + display: flex; + flex-direction: column; + gap: 0.65rem; +} + +.editorialKicker { + font-size: 0.68rem; + color: var(--accent-coral, #e07256); + font-weight: 700; + letter-spacing: 0.1em; + text-transform: uppercase; +} + +.editorialHeading { + font-family: var(--font-playfair), 'Playfair Display', serif; + font-size: 1.35rem; + font-weight: 700; + color: var(--text-primary, #1a1612); + margin: 0; + line-height: 1.25; +} + +.editorialText p { + font-size: 0.92rem; + color: var(--text-secondary, #5c564d); + line-height: 1.6; + margin: 0; +} + +.factbox { + background: var(--bg-secondary, #f3ede4); + border-radius: 10px; + padding: 1.25rem; + display: flex; + flex-direction: column; + gap: 0; +} + +.factboxHeading { + font-family: var(--font-playfair), 'Playfair Display', serif; + font-size: 1rem; + font-weight: 700; + color: var(--text-primary, #1a1612); + margin: 0 0 0.85rem; +} + +.factRow { + display: flex; + justify-content: space-between; + align-items: baseline; + padding: 0.5rem 0; + border-bottom: 1px solid var(--border-color, #e5dfd5); + font-size: 0.85rem; + gap: 0.5rem; +} + +.factRow:last-child { + border-bottom: none; +} + +.factKey { + color: var(--text-muted, #6d685f); +} + +.factVal { + font-family: var(--font-playfair), 'Playfair Display', serif; + font-weight: 700; + color: var(--text-primary, #1a1612); + text-align: right; +} + +@media (max-width: 768px) { + .editorialGrid { + grid-template-columns: 1fr; + padding: 1.25rem; + gap: 1.25rem; + } +} + .resultsHeader { display: flex; align-items: center; diff --git a/nextjs-app/components/HomeView.tsx b/nextjs-app/components/HomeView.tsx index 91b4aad..aedb624 100644 --- a/nextjs-app/components/HomeView.tsx +++ b/nextjs-app/components/HomeView.tsx @@ -5,7 +5,7 @@ 'use client'; -import React, { useState, useEffect, useRef } from 'react'; +import React, { useState, useEffect, useRef, useCallback } from 'react'; import { useSearchParams, useRouter, usePathname } from 'next/navigation'; import { FilterBar } from './FilterBar'; import { SchoolRow } from './SchoolRow'; @@ -41,6 +41,8 @@ export function HomeView({ initialSchools, filters, totalSchools }: HomeViewProp const [mapSchools, setMapSchools] = useState([]); const [isLoadingMap, setIsLoadingMap] = useState(false); const prevSearchParamsRef = useRef(searchParams.toString()); + const [geoState, setGeoState] = useState<'idle' | 'requesting' | 'error'>('idle'); + const [geoError, setGeoError] = useState(null); const hasSearch = searchParams.get('search') || searchParams.get('postcode'); const isLocationSearch = !!searchParams.get('postcode'); @@ -117,6 +119,47 @@ export function HomeView({ initialSchools, filters, totalSchools }: HomeViewProp } }; + const handleNearMe = useCallback(() => { + if (!navigator.geolocation) { + setGeoState('error'); + setGeoError('Geolocation is not supported by your browser. Enter a postcode instead.'); + return; + } + setGeoState('requesting'); + setGeoError(null); + navigator.geolocation.getCurrentPosition( + async (position) => { + const { latitude, longitude } = position.coords; + try { + const res = await fetch( + `https://api.postcodes.io/postcodes?lon=${longitude}&lat=${latitude}&limit=1` + ); + const data = await res.json(); + if (data.result && data.result.length > 0) { + const postcode = data.result[0].postcode as string; + setGeoState('idle'); + router.push(`/?postcode=${encodeURIComponent(postcode)}&radius=1`); + } else { + setGeoState('error'); + setGeoError('No postcode found near your location. Try entering one above.'); + } + } catch { + setGeoState('error'); + setGeoError('Could not look up your location. Please try again.'); + } + }, + (err) => { + setGeoState('error'); + if (err.code === err.PERMISSION_DENIED) { + setGeoError('Location access was denied. Enter a postcode above to find nearby schools.'); + } else { + setGeoError('Could not get your location. Please try again or enter a postcode.'); + } + }, + { timeout: 10000, maximumAge: 60000 } + ); + }, [router]); + const sortedSchools = [...allSchools].sort((a, b) => { if (sortOrder === 'rwm_desc') return (b.rwm_expected_pct ?? -Infinity) - (a.rwm_expected_pct ?? -Infinity); if (sortOrder === 'rwm_asc') return (a.rwm_expected_pct ?? Infinity) - (b.rwm_expected_pct ?? Infinity); @@ -132,8 +175,16 @@ export function HomeView({ initialSchools, filters, totalSchools }: HomeViewProp {/* Combined Hero + Search and Filters */} {!isSearchActive && (
-

Find Local Schools

-

Compare school results (SATs and GCSE), for thousands of schools across England

+ + +

+ Every English school, compared. +

+

+ 24,000+ primary and secondary schools with Key Stage 2 SATs, GCSE results, Ofsted grades, progress scores and admissions data — side by side, in one place. +

)} @@ -146,17 +197,214 @@ export function HomeView({ initialSchools, filters, totalSchools }: HomeViewProp {/* Discovery section shown on landing page before any search */} {!isSearchActive && initialSchools.schools.length === 0 && (
- {totalSchools &&

{totalSchools.toLocaleString()}+ primary and secondary schools across England

} -

Try searching for a school name, or enter a postcode to find schools near you.

-
- Quick searches: - {['Manchester', 'Bristol', 'Leeds', 'Birmingham'].map(city => ( - {city} - ))} +
+ + {geoError &&

{geoError}

} +
+
)} + {/* How it works — only on landing page */} + {!isSearchActive && ( +
+
+

What you'll see on every school

+ Primary or secondary — the page adapts to the phase +
+
+ + {/* Card 1 — Performance */} +
+
+ {/* Primary: mini cascade */} +
+
Primary · Year 6 · Key Stage 2 SATs
+
+ {[ + { subj: 'Reading', exp: 96, exc: 73, nat: 75 }, + { subj: 'Writing', exp: 81, exc: 15, nat: 72 }, + { subj: 'Maths', exp: 85, exc: 47, nat: 74 }, + ].map(({ subj, exp, exc, nat }) => ( +
+
{subj}
+
Expected{exp}%
+
+
{nat}%
+
+
+
Exceeding{exc}%
+
+
+
+
+ ))} +
+
+ {/* Secondary: Attainment 8 */} +
+
Secondary · Year 11 · GCSE Attainment 8
+
+
+
This schoolNational avg 50.2
+
+
+
+
+
+
+
62.4
+
+12.2 vs national
+
+
+
+
+
+
Performance
+
Results against the national average
+

For primary schools, each subject's Expected and Exceeding percentages side by side. For secondary schools, GCSE Attainment 8 with the national benchmark overlaid.

+
+
+ + {/* Card 2 — Ofsted */} +
+
+
+
+ + Latest Ofsted inspection +
+ OUTSTANDING +
Rated Outstanding at last inspection.
+
Full inspection · March 2024
+
+
+
+
Judgement
+
Ofsted at a glance
+

Current grade, inspection date, and a plain-English headline — without opening a 40-page report.

+
+
+ + {/* Card 3 — Compare */} +
+
+
+
+
Metric
+
Our Lady
Queen of Heaven
+
St Mary's
Catholic Primary
+
+ {[ + { label: 'Reading, Writing & Maths', a: '70%', b: '64%', aHi: true }, + { label: 'Ofsted', a: 'Outstanding', b: 'Good', aHi: true }, + { label: 'Reading progress', a: '+2.1', b: '+0.4', aHi: true }, + ].map(({ label, a, b, aHi }) => ( +
+ {label} + {a} + {b} +
+ ))} +
+ pin up to 5 schools
+
+
+
+
Compare
+
Side-by-side shortlists
+

Pin up to five schools and every metric aligns in the same columns — works for primary and secondary alike.

+
+
+ +
+
+ )} + + {/* Editorial — only on landing page */} + {!isSearchActive && ( +
+
+
+
About school data
+

Making UK school performance data actually readable

+

+ School performance data in England is rich but fragmented. The Department for Education publishes + Key Stage 2 SATs, GCSE attainment, Ofsted outcomes, progress scores, admissions figures and + demographics — each in its own table, each with its own jargon. +

+

+ SchoolCompare brings it all into one place. Every school page shows performance against the national + average, explains what the numbers mean, and lets you shortlist schools side by side. Built for + parents, governors, journalists, and anyone who wants to understand a school without reading a + 40-page inspection report. +

+
+
+

Coverage at a glance

+
+ Schools covered + {totalSchools ? `${totalSchools.toLocaleString()}` : '24,000+'} +
+
+ Local authorities + {filters.local_authorities.length > 0 ? filters.local_authorities.length : 152} +
+
+ Phases + Primary & Secondary +
+
+ Latest results year + 2024/25 +
+
+ Historical data + 2016–2025 +
+
+ Metrics per school + 40+ +
+
+
+
+ )} + {/* Results Section */}
{!hasSearch && initialSchools.schools.length > 0 && (