Stop 22 · Build Portfolio ProjectsProjects · 11/15

Video Streaming UI

Part of the Frontend Developer Roadmap

In short

Netflix-style rows, a hover preview and a custom player. This project is all about performance: dozens of images, heavy video, and a UI that still scrolls smoothly on a budget phone.

A Netflix/YouTube-style interface — video grid, custom player controls, and category browsing — strong practice for media-heavy, performance-sensitive UI.

The jaadu on a sofa holds a remote in front of a TV showing a colourful cartoon scene.

Think of it like this

Flipping channels on the family TV

Everyone wants to see what's on before committing, nobody wants to wait, and Dadi needs big, simple buttons. Your streaming UI has the same audience: quick previews, instant start, easy controls.

Watch it happen

Custom controls talking to the video

Viewer
Controls
<video>

click play/pause

1/6The viewer clicks play. toggle() checks ref.current.paused.

The big ideas

What you need to know

Custom player controls

Play, seek, volume, speed and fullscreen built on the video element. Proves you know browser media APIs.

Fast thumbnail rows

Lazy-loaded, correctly sized images in horizontal rows. Shows performance awareness.

Keyboard shortcuts

Space to pause, arrows to seek, F for fullscreen, like real players.

Streaming formats

Long videos usually stream as HLS. A library like hls.js plays it in browsers without native support.

How it works

Build plan

  1. 1

    Home page rows

    Categories with horizontally scrolling thumbnails.

  2. 2

    Watch page

    A video element with a sample video URL.

  3. 3

    Custom controls

    Hide default controls and build your own bar.

  4. 4

    Continue watching

    Save progress per video and resume from there.

  5. 5

    Performance pass

    Lighthouse check, lazy images, responsive sizes.

See it in code

Walk through the code

jsx
1function Player({ src }) {2  const ref = useRef(null);3  const [progress, setProgress] = useState(0);4 5  const toggle = () => (ref.current.paused ? ref.current.play() : ref.current.pause());6  const onTime = () => setProgress(ref.current.currentTime / ref.current.duration);7  const seek = (e) => { ref.current.currentTime = e.target.value * ref.current.duration; };8 9  return (10    <div>11      <video ref={ref} src={src} onTimeUpdate={onTime} onClick={toggle} />12      <button onClick={toggle} aria-label="Play or pause">Play / Pause</button>13      <input type="range" min="0" max="1" step="0.001" value={progress} onChange={seek} aria-label="Seek" />14    </div>15  );16}

1/4A ref to the real video element, plus progress from 0 to 1.

The video element does the heavy lifting. You read currentTime and duration for progress, and set currentTime to seek. Add aria-labels so icon buttons make sense to screen readers.

Save yourself the pain

Common mistakes

Oops

Expecting autoplay with sound to work on page load.

Do this instead

Browsers usually block autoplay with sound. Start muted, or wait for the user to press play.

Oops

Loading full-size posters for tiny thumbnails.

Do this instead

Serve small images with srcset or next/image, and lazy-load rows below the fold.

Your mission

Milestone 1: your own play button

~40 min

Quick check

Your video won't autoplay on page load in Chrome, but it plays when you click. What's the usual fix?

Go deeper

  1. 1Build custom video player controls (play, seek, volume, fullscreen).
  2. 2Implement lazy-loaded thumbnail grids with hover-preview behavior.
  3. 3Pay close attention to performance — this project type is easy to make janky.

More projects at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge