A browser-based multi screen YouTube player built with vanilla JavaScript, Tailwind CSS, and DaisyUI. This project was created as a frontend learning exercise exploring iframe embedding, DOM manipulation, randomisation techniques, and UI component design.
👉 https://ytsandbox.netlify.app
This is a great beginner-to-intermediate project for understanding several core web concepts:
The core of this app is JavaScript creating HTML elements on the fly — no frameworks, no virtual DOM.
let div = document.createElement('div');
const iframe = document.createElement('iframe');
div.appendChild(iframe);
playerContainer.appendChild(div);You'll learn how to build and inject elements programmatically rather than hardcoding HTML.
The getID() function uses a regular expression to extract YouTube video IDs from multiple URL formats:
const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=|shorts\/)([^#&?]*).*/;This handles all these formats:
https://www.youtube.com/watch?v=abc123https://youtu.be/abc123https://www.youtube.com/shorts/abc123
Concept: Regex capture groups, URL structure, string matching.
Each player is an <iframe> pointed at YouTube's embed API with query strings controlling behaviour:
https://www.youtube.com/embed/{videoId}?autoplay=1&mute=1&start=7&rel=0&widget_referrer=https://...
| Parameter | Purpose |
|---|---|
autoplay |
Starts video on load |
mute |
Required for autoplay in most browsers |
start |
Random start time in seconds |
rel |
Disables related videos |
widget_referrer |
Simulates traffic source |
Concept: Third-party embed APIs, query strings, iframe sandbox behaviour.
Rather than spawning all iframes at once (which would hammer the browser), each player loads with a delay:
setTimeout(() => {
// create and append iframe
}, i * 1500);This is a simple form of rate limiting / throttling — a real-world pattern used in APIs and UI rendering.
Concept: Event loop, non-blocking execution, performance-conscious rendering.
Two randomisation strategies are used:
const randomRef = platforms[Math.floor(Math.random() * platforms.length)]; // random array item
const randomStart = Math.floor(Math.random() * 15); // random number in rangeConcept: Math.random(), array indexing, seeding variation in repeated operations.
The UI uses DaisyUI's component library layered on top of Tailwind utility classes:
<div class="card bg-base-100 shadow-xl">
<div class="card-body text-center">The data-theme="halloween" attribute on <html> switches the entire app's colour scheme — one of DaisyUI's built-in themes.
Concept: Utility-first CSS, theming systems, component libraries.
The player grid uses Tailwind's responsive grid system:
<div class="grid grid-cols-2 md:grid-cols-5 gap-4">- Mobile: 2 columns
- Desktop (
mdbreakpoint): 5 columns
Concept: CSS Grid, responsive breakpoints, mobile-first design.
| Technology | Role |
|---|---|
| HTML5 | Structure |
| Vanilla JavaScript | Logic & DOM manipulation |
| Tailwind CSS (CDN) | Utility styling |
| DaisyUI | Pre-built UI components |
| YouTube Embed API | Video playback |
| Google Analytics | Usage tracking |
| Google AdSense | Monetisation layer |
yt-sandbox/
├── index.html # Entire app — single file architecture
└── logo.png # Favicon / brand logo
This is a single-file application — a common pattern for simple tools where the overhead of a build system (React, Vite, etc.) isn't justified.
No installation needed. Open index.html directly in a browser, or deploy to any static host:
- Netlify — drag and drop the folder
- GitHub Pages — push to a
gh-pagesbranch - Vercel — connect your repo
- Autoplay with sound is blocked by most modern browsers unless the user has interacted with the page first. This is a browser security policy — the
muteoption works around it. - Iframe sandboxing — some websites block being loaded inside iframes via
X-Frame-Optionsheaders. YouTube explicitly allows embedding via their embed endpoint. - Heavy use of iframes is resource intensive — CPU and memory usage scales with player count.
- Add a progress tracker showing which players have finished loading
- Implement a stop all / reset button that clears the player grid
- Store recent URLs in localStorage
- Add a fullscreen toggle per player
- Rewrite logic as a React component with
useStateanduseEffectfor practice - Add a playlist mode that queues multiple video IDs
Built by Team Keo — a final-year Computing Systems student project exploring frontend JavaScript and browser-based media tooling.
Credit & inspiration: https://github.com/pooreyoutuber
This project is intended for educational and experimental purposes.