Build it as a semantic, responsive shell
You just ran npm create vite@latest and got a blinking counter button on a blank page.
What you'll build
A static, fully semantic, mobile-first responsive Pulse shell (header/nav, main with a metrics grid placeholder and an events list placeholder, footer) with a correct landmark structure, an unbroken heading order, and colors that pass WCAG AA contrast, verified in the browser at 360px, 768px, and desktop widths.
See how we teach, before you sign up
You don't just get code dumped on you. Every starter file and every solution is explained line-by-line, in plain English. Here's one real file from this project:
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App';
const rootElement = document.getElementById('root');
if (!rootElement) {
throw new Error('Root element #root was not found in index.html');
}
createRoot(rootElement).render(
<StrictMode>
<App />
</StrictMode>
);
Reading this file
createRoot(rootElement)React 18's root API. Vite's react-ts template already wires this up, one less thing you have to configure.if (!rootElement) {Fail loudly instead of silently rendering nothing if index.html's #root div is ever renamed or removed.<StrictMode>Double-invokes some lifecycle work in development only, to surface side effects that are not pure. Does not affect production output.import './index.css';Global stylesheet is imported once here so it loads before App renders, order matters for CSS specificity.
The entry point that mounts App into #root. You will not need to change this file this rung, but understand what it does before you touch App.tsx.
That's 1 of 6 explained code blocks in this single project.
The build, milestone by milestone
- 1
Scaffold the project and read what you got
4 guided stepsEvery later rung assumes you understand this base: how main.tsx mounts App, how index.html's single #root div is the entire initial page, and how the dev server hot-reloads. Skipping this step means later debugging (why isn't my CSS loading, why is nothing rendering) has no foundation.
- 2
Replace the div soup with real landmarks
5 guided stepsLandmarks are how a screen reader user jumps straight to main content or navigation instead of tabbing through everything linearly. A div with a className that says nav is invisible to assistive tech, only the real nav element is announced as navigation.
- 3
Lay out the metrics grid and events list
5 guided stepsA product manager scanning Pulse on a phone needs the four headline metrics to stack cleanly in one column before any responsive work happens, mobile-first means you write the narrow-screen layout as the default and add width upward from there, not the other way around.
- 4
Make it responsive from 360px up
5 guided stepsMobile-first means the base styles (already written in milestone 3) are the narrow-screen truth, and media queries only ever add columns or space as the viewport grows, this is why you write min-width queries, not max-width ones.
- 5
Run the accessibility and contrast pass
5 guided stepsA responsive, semantically correct shell can still fail real users if the muted gray text is too light to read, or if a keyboard user has to tab through the entire nav before reaching the main content on every single page. This pass catches both.
What's inside when you start
You'll walk away with
This is portfolio-grade. Build it free.
Sign up to unlock every milestone step-by-step, the code skeletons, full reference solutions, and checkable tasks, with your progress saved as you build.
Start building