use-picture-in-picture
Hook for managing Picture-in-Picture mode with full browser support
Installation
Install the hook
npx shadcn add @limeplay/use-picture-in-pictureAdd Event & Action Bridge
Import the usePictureInPictureStates hook in your existing PlayerHooks component.
import React from "react"
import { usePictureInPictureStates } from "@/hooks/limeplay/use-picture-in-picture"
import { usePlaybackStates } from "@/hooks/limeplay/use-playback"
import { usePlayerStates } from "@/hooks/limeplay/use-player"
export const PlayerHooks = React.memo(() => {
usePlayerStates()
usePlaybackStates()
usePictureInPictureStates()
return null
})Add the Store States
import { createPictureInPictureStore, PictureInPictureStore } from "@/hooks/limeplay/use-picture-in-picture"
export type TypeMediaStore = PictureInPictureStore &
{}
export function createMediaStore(initProps?: Partial<CreateMediaStoreProps>) {
const mediaStore = create<TypeMediaStore>()((...etc) => ({
...createPictureInPictureStore(...etc),
...initProps,
}))
return mediaStore
}Example Usage
Use the usePictureInPicture() hook to control Picture-in-Picture mode programmatically.
import { usePictureInPicture } from "@/hooks/limeplay/use-picture-in-picture"
import { useMediaStore } from "@/components/limeplay/media-provider"
export function CustomPipButton() {
const { togglePictureInPicture, enterPictureInPicture, exitPictureInPicture } = usePictureInPicture()
const isPictureInPictureActive = useMediaStore((state) => state.isPictureInPictureActive)
const isPictureInPictureSupported = useMediaStore((state) => state.isPictureInPictureSupported)
if (!isPictureInPictureSupported) {
return null // Browser doesn't support PiP
}
return (
<div>
<button onClick={togglePictureInPicture}>
{isPictureInPictureActive ? "Exit PiP" : "Enter PiP"}
</button>
</div>
)
}Understanding
The use-picture-in-picture hook enables Picture-in-Picture functionality for video elements. It implements the Event & Action Bridge pattern:
- Event Bridge:
usePictureInPictureStates()listens to native PiP events (enterpictureinpicture,leavepictureinpicture) and synchronizes state to the React store - Action Bridge:
usePictureInPicture()provides control functions to enter, exit, or toggle PiP mode
Browser API Support
The hook automatically handles different browser implementations:
- Standard API: Modern browsers (Chrome, Edge) use
document.pictureInPictureElementandvideo.requestPictureInPicture() - Webkit API: Safari uses
video.webkitSetPresentationMode()andvideo.webkitPresentationMode
Browser Support
Picture-in-Picture only works with <video> elements. The hook validates this at runtime.
API Reference
usePictureInPictureStates()
Sets up event listeners for Picture-in-Picture events. This hook should be called once in your PlayerHooks component. It automatically syncs the following state:
isPictureInPictureActive- Whether PiP mode is currently activeisPictureInPictureSupported- Whether the browser supports PiP
usePictureInPicture()
Returns control functions for managing Picture-in-Picture mode.
Returns
Prop
Type
Store State
The Picture-in-Picture store provides the following state accessed via useMediaStore:
Prop
Type
Event Callbacks
You can listen to PiP events by setting callbacks in the store:
store.setState({
onEnterPictureInPicture: () => {
console.log("Entered Picture-in-Picture mode")
},
onLeavePictureInPicture: () => {
console.log("Exited Picture-in-Picture mode")
},
})