Skip to main content

React β€” NHS Quickstart

βš›οΈ React Β· Vite Β· Fetch APIs Β· Tables & Charts Β· NHS.UK styling
Why React in the NHS

Perfect for thin internal tools: list views over KPIs, form-based admin, and embedding charts from APIs that sit in front of SQL Server. Keep secrets on the server; React only calls your internal API.

Great for: Developer Β· BI Analyst (with a service) Β· Data Scientist (model explorer).


βš™οΈ 10-minute install​

Create a lightweight React app with Vite.

npm create vite@latest nhs-react -- --template react
cd nhs-react
npm install
npm run dev

Open the URL printed in the terminal.


πŸš€ β€œHello NHS” β€” call a KPI API and render a table​

Create .env.local (gitignored):

.env.local
VITE_API_URL=http://localhost:8000
VITE_API_KEY=dev-local-key

Replace src/App.jsx with:

src/App.jsx
import { useEffect, useState } from 'react'

export default function App(){
const [rows, setRows] = useState([])
const [error, setError] = useState(null)
const [loading, setLoading] = useState(true)

useEffect(() => {
const url = (import.meta.env.VITE_API_URL || '') + '/kpi'
const headers = {}
if (import.meta.env.VITE_API_KEY) headers['x-api-key'] = import.meta.env.VITE_API_KEY

fetch(url, { headers, cache: 'no-store' })
.then(r => { if(!r.ok) throw new Error('Fetch failed'); return r.json() })
.then(d => setRows(d.rows || d))
.catch(e => setError(e.message))
.finally(() => setLoading(false))
}, [])

if (loading) return <main style={{padding:16}}><p>Loading…</p></main>
if (error) return <main style={{padding:16}}><p role="alert">Error: {error}</p></main>

return (
<main className="nhsuk-width-container" style={{padding:16}}>
<h2>NHS KPI</h2>
<small>Data last updated from API on page load.</small>
<table role="table" style={{borderCollapse:'collapse', width:'100%'}}>
<thead>
<tr>
<th style={{textAlign:'left'}}>Practice</th>
<th>Total</th>
<th>Attendance</th>
<th>Median wait (min)</th>
</tr>
</thead>
<tbody>
{rows.map(r => (
<tr key={r.practice_id}>
<td>{r.practice_id}</td>
<td>{r.total_appointments}</td>
<td>{r.attendance_rate != null ? (r.attendance_rate * 100).toFixed(1) + '%' : 'β€”'}</td>
<td>{r.median_wait_minutes ?? 'β€”'}</td>
</tr>
))}
</tbody>
</table>
</main>
)
}

Run the app:

npm run dev

This expects a local API (e.g., FastAPI or Express) with a /kpi endpoint. See See also below.


πŸ“Š Charts & tables​

For sortable/filterable tables without heavy dependencies.

npm i @tanstack/react-table
// Example sketch (see TanStack docs for full usage)
/*
import { useReactTable, getCoreRowModel, getSortedRowModel, flexRender } from '@tanstack/react-table'
// define columns, data, and render a table with sortable headers
*/

πŸ” Auth, CORS, and SSO​

  • Keep SQL access on the server (FastAPI/Express). React talks to your API only.
  • For dev, allow a temporary API key header. In prod, protect with Entra ID (Azure AD) and serve the UI behind SSO.
  • Lock CORS on the API to your app’s origin (e.g., intranet domain).

🧱 Styling & NHS branding​

  • Use @nhsuk/frontend CSS for consistent typography and colour.
  • Or Tailwind for utility classes; keep contrast and accessible focus states.

Global CSS import example (Vite)

src/main.css
@import "@nhsuk/frontend/dist/nhsuk.css";

Add to src/main.jsx:

import './main.css'

🐳 Docker (optional for static hosting)​

For Vite builds, you can produce a static site and serve via NGINX.

Dockerfile

# Build
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Serve
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Deploy to Azure Static Web Apps, S3 + CloudFront, or behind IIS/NGINX on the intranet.


πŸ”’ IG & safety checklist​

  • No secrets in React code; everything sensitive stays server-side.
  • Suppress small numbers at the API; don’t compute PHI in the browser.
  • Version UI + API together; document endpoint owners and retention.
  • Ensure component libraries meet a11y standards; test keyboard + screen reader paths.

πŸ“ Measuring impact​

  • TTI and Lighthouse scores for key pages.
  • Error rate from API calls (network + 5xx).
  • Adoption: users per week; tasks completed.
  • Change lead time: PR opened β†’ deployed.

πŸ”— See also​

See also: FastAPI Β· Express.js Β· Next.js Β· Docker Β· Secrets & .env

What’s next?

You’ve completed the Learn β€” React stage. Keep momentum: