
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
A React component for playing a variety of URLs, including file paths, YouTube, Facebook, Vimeo, Bunny Stream and etc..
A modern, customizable video player component for React that supports multiple video services including YouTube, Vimeo, Bunny Stream, Google Drive, Mux, and more. Built with TypeScript and featuring a beautiful, responsive UI with custom controls.
npm install playstack
# or
yarn add playstack
To use the custom player controls, you need to import the CSS styles:
import 'playstack/dist/style.css';
Note: The CSS import is required for the custom controls to display properly. Without it, the player will still function but will use the default styling of the underlying video platforms.
import { Player } from 'playstack';
function App() {
return (
<Player
src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
onTimeUpdate={(time) => console.log('Current time:', time.current)}
/>
);
}
import { Player } from 'playstack';
function App() {
return (
<Player
src="https://vimeo.com/123456789"
onTimeUpdate={(time) => console.log('Current time:', time.current)}
/>
);
}
Important: Bunny Stream requires both src (iframe URL) and config.bunny props to work properly. If src is not provided, the player will show a loading indicator indefinitely.
import { Player } from 'playstack';
function App() {
return (
<Player
src="https://iframe.mediadelivery.net/embed/your-library/your-video-id"
config={{
bunny: {
id: 'your-video-id',
hostname: 'your-library.b-cdn.net'
}
}}
onTimeUpdate={(time) => console.log('Current time:', time.current)}
/>
);
}
| Prop | Type | Default | Description |
|---|---|---|---|
src | string | - | Direct video URL (YouTube, Vimeo, Mux, HLS, DASH, direct video, etc.) or Bunny Stream iframe URL |
config | object | - | Configuration object (see below) |
config.bunny | { id: string; hostname: string } | - | Bunny Stream configuration (requires src to be provided) |
config.youtube | object | - | YouTube-specific configuration (see below) |
config.youtube.noCookie | boolean | true | Use YouTube's privacy-enhanced mode (youtube-nocookie.com). Set to false to use youtube.com. Note: YouTube Shorts always use youtube.com regardless of this setting. |
config.theme | string | '#00B2FF' | Theme color for player controls (YouTube, Vimeo, and direct video platforms only) |
config.defaultControls | boolean | false | Use default platform controls instead of custom controls |
config.hidePlayerControls | boolean | false | Hide all player controls (overlay and controls bar) |
onTimeUpdate | (time: { current: number; duration: number }) => void | - | Callback for time updates |
onDurationChange | (duration: number) => void | - | Callback when video duration is available |
onTitleChange | (title?: string) => void | - | Callback when video title is available (YouTube and Vimeo only) |
onReady | (player: any) => void | - | Callback when player is ready (receives player instance) |
onVolumeChange | (data: { volume: number; muted: boolean }) => void | - | Callback when volume or mute state changes (does not work on Bunny Stream and Google Drive) |
onPlaybackRateChange | (playbackRate: number) => void | - | Callback when playback rate changes (does not work on Bunny Stream and Google Drive) |
onStateChange | (state: 'playing' | 'paused' | 'buffering') => void | - | Callback when player state changes |
The Player component supports ref forwarding. You can use a callback function that receives the player object.
Note: The ref receives different player objects depending on the platform:
playVideo(), pauseVideo(), seekTo(), etc.play(), pause(), setCurrentTime(), etc.play(), pause(), seekTo(), setVolume(), etc.Features: Full YouTube support including Shorts, automatic thumbnail generation
URL Formats: Standard YouTube URLs, YouTube Shorts, YouTube-nocookie
Usage: Simply pass the YouTube URL to the src prop
Theme Support: ✅ Full theme customization
iOS Fullscreen: ✅ Native fullscreen support on iOS (video automatically enters fullscreen when playback starts)
Privacy Mode: By default, uses YouTube's privacy-enhanced mode (youtube-nocookie.com). You can disable this by setting config.youtube.noCookie to false. Note: YouTube Shorts always use youtube.com regardless of this setting.
Example:
<Player src="https://www.youtube.com/watch?v=dQw4w9WgXcQ" />
<Player src="https://youtu.be/dQw4w9WgXcQ" />
<Player src="https://www.youtube.com/shorts/dQw4w9WgXcQ" />
// Use regular YouTube domain (not privacy-enhanced)
<Player
src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
config={{ youtube: { noCookie: false } }}
/>
src prop<Player src="https://vimeo.com/123456789" />
<Player src="https://player.vimeo.com/video/123456789" />
<Player src="https://vimeo.com/channels/staffpicks/123456789" />
src (iframe URL) and config.bunny (configuration) props must be provided<Player
src="https://iframe.mediadelivery.net/embed/your-library/your-video-id"
config={{
bunny: {
id: 'your-video-id',
hostname: 'your-library.b-cdn.net'
}
}}
/>
src is missing, the player will display a loading indicator.m3u8 if needed)<Player src="https://stream.mux.com/your-video-id" />
<Player src="https://stream.mux.com/your-video-id.m3u8" />
<Player src="https://example.com/video.mp4" />
<Player src="https://example.com/stream.m3u8" />
<Player src="https://example.com/stream.mpd" />
| Key | Action |
|---|---|
Space | Play/Pause |
← | Rewind 10 seconds |
→ | Forward 10 seconds |
↑ | Increase volume |
↓ | Decrease volume |
M | Mute/Unmute |
Note: On iOS devices, the volume bar is hidden for custom controls because browsers do not allow programmatic volume control.
Note: Theme customization only works with YouTube, Vimeo, and direct video platforms.
<Player src="https://www.youtube.com/watch?v=dQw4w9WgXcQ" config={{ theme: '#FF6B6B' }} />
By default, the player uses YouTube's privacy-enhanced mode (youtube-nocookie.com) which doesn't store cookies. You can disable this to use the regular YouTube domain:
<Player
src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
config={{ youtube: { noCookie: false } }}
/>
Note: YouTube Shorts always use youtube.com regardless of the noCookie setting.
You can use the platform's default controls instead of custom controls:
<Player src="https://www.youtube.com/watch?v=dQw4w9WgXcQ" config={{ defaultControls: true }} />
You can hide all custom controls:
<Player src="https://www.youtube.com/watch?v=dQw4w9WgXcQ" config={{ hidePlayerControls: true }} />
<Player
src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
onTimeUpdate={(time) => {
console.log(`Progress: ${time.current}/${time.duration}`);
// Save progress to localStorage, analytics, etc.
}}
/>
<Player
src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
onDurationChange={(duration) => {
console.log(`Video duration: ${duration} seconds`);
}}
/>
Note: Title extraction only works with YouTube and Vimeo platforms.
<Player
src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
onTitleChange={(title) => {
document.title = `Watching: ${title}`;
}}
/>
<Player
src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
onReady={(player) => {
console.log('Player ready:', player);
// Access player methods directly
// player.play(), player.pause(), etc.
}}
/>
<Player
src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
onVolumeChange={({ volume, muted }) => {
console.log(`Volume: ${volume}, Muted: ${muted}`);
}}
onPlaybackRateChange={(rate) => {
console.log(`Playback rate: ${rate}x`);
}}
/>
Note: onVolumeChange and onPlaybackRateChange do not work with Bunny Stream and Google Drive.
<Player
src="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
onStateChange={(state) => {
console.log(`Player state: ${state}`);
// state is one of: 'playing', 'paused', 'buffering'
}}
/>
iOS Safari:
Android Chrome: Standard fullscreen APIs with touch-friendly controls
Touch Controls: Gesture support across all platforms
This project builds upon the excellent work of:
MIT License - see LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
Need help? We're here to assist you!
Before opening an issue, please:
FAQs
A React component for playing a variety of URLs, including file paths, YouTube, Facebook, Vimeo, Bunny Stream and etc..
The npm package playstack receives a total of 27 weekly downloads. As such, playstack popularity was classified as not popular.
We found that playstack demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.