Nike React Landing Page
Pixel-perfect brand UI — zero custom CSS, pure Tailwind.
Overview
Replicating a major brand's landing page is one of the most direct ways to sharpen front-end precision. Nike's design system relies on large typography, full-bleed imagery, and tight grid discipline. This project reproduced the layout entirely in React and Tailwind CSS, with zero custom CSS files, proving that utility-class systems can match the fidelity of hand-crafted stylesheets.
The Problem
Developers often reach for custom CSS when Tailwind classes feel limiting, leading to split styling concerns that are hard to maintain. The challenge here was to demonstrate that Tailwind's utility system — used correctly — can achieve full design fidelity for a production-grade marketing page without a single custom class definition.
The Solution
Decomposed the page into atomic React components — HeroBanner, ProductCard, NavBar, ColourSwatch, and CTAButton — each styled exclusively with Tailwind utilities. Used Tailwind's responsive prefix system for all breakpoint adaptations. Implemented scroll-triggered entrance animations using the native Intersection Observer API to avoid adding a motion library.
Key Features
- Fully responsive across mobile, tablet, and desktop — Tailwind responsive prefixes only
- Hero section with large product imagery, typographic overlay, and CTA buttons
- Product card grid with hover zoom, colour variant selectors, and add-to-cart states
- Smooth scroll-triggered entrance animations via Intersection Observer API
- Reusable NavBar, ProductCard, and CTAButton components with clear prop interfaces
- Zero custom CSS — 100% Tailwind utility classes
- Lazy-loaded product images for fast initial page render
Challenges & Learnings
Achieving consistent spacing and alignment across all three breakpoints without custom media queries pushed me to fully internalise Tailwind's spacing scale. The colour swatch hover interaction on product cards required per-card local state that couldn't be lifted without creating unnecessary re-renders; solved by encapsulating swatch state inside each ProductCard component. Performance was also a consideration: wrapping the ProductCard in React.memo prevented unnecessary re-renders when parent state changed during scroll animation callbacks.
Tech Stack
Frontend
Build
Animations
Architecture
More Projects