@coderusecode/react-native-mini-player
v0.2.0
Published
Netflix/YouTube-style floating mini video player for React Native with continuous playback
Maintainers
Readme
@coderusecode/react-native-mini-player
Netflix / YouTube–style floating mini video player for React Native.
One persistent react-native-video surface morphs between inline, mini, and fullscreen with Reanimated — playback never restarts during minimize, expand, drag, or navigation.
Modes
- Standalone:
<MiniPlayer />— the package owns the video (simple apps). - Integration:
<VideoHost />+<PlayerAnchor />— attach mini-player UX to an existing player flow with a single shared video instance across React Navigation.
Features
- Floating mini player with expand ↔ minimize
- Drag anywhere · snap to edges · swipe to dismiss
- Continuous playback (no remount, no black flash)
- Persists across screens; expand restores the origin route + anchor
- Gesture Handler + Reanimated (UI-thread)
- Customizable layout, theme, icons, and controls
- TypeScript · hooks API · light/dark themes
Installation
npm install @coderusecode/react-native-mini-player react-native-video react-native-reanimated react-native-gesture-handler react-native-safe-area-contextBabel (Reanimated)
// babel.config.js
module.exports = {
presets: ['module:@react-native/babel-preset'],
plugins: ['react-native-reanimated/plugin'], // must be last
};Entry (Gesture Handler)
// index.js
import 'react-native-gesture-handler';
import { AppRegistry } from 'react-native';
import App from './App';
AppRegistry.registerComponent('App', () => App);Wrap your app with GestureHandlerRootView and SafeAreaProvider.
Quick start
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import {
MiniPlayerProvider,
MiniPlayer,
useMiniPlayerControls,
} from '@coderusecode/react-native-mini-player';
export default function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<SafeAreaProvider>
<MiniPlayerProvider theme="dark">
<Home />
<MiniPlayer
source={{ uri: 'https://example.com/video.mp4' }}
visible
draggable
snapToEdge
swipeToClose
animation="spring"
onClose={() => {}}
onExpand={() => {}}
onMinimize={() => {}}
/>
</MiniPlayerProvider>
</SafeAreaProvider>
</GestureHandlerRootView>
);
}Hooks
const { mode, expand, minimize, close } = useMiniPlayer();
const { play, pause, togglePlay, seek, isPlaying } = useMiniPlayerControls();API
<MiniPlayerProvider>
| Prop | Type | Default |
|------|------|---------|
| theme | 'light' \| 'dark' \| MiniPlayerTheme | 'dark' |
| initialVisible | boolean | false |
| initialMode | 'inline' \| 'mini' \| 'fullscreen' | 'mini' |
| onExpandNavigate | (origin) => void \| Promise<void> | — |
| expandFallback | 'fullscreen' \| 'mini' \| 'close' \| fn | 'fullscreen' |
Integration Mode
<MiniPlayerProvider onExpandNavigate={(o) => navRef.navigate(o.routeName, o.params)}>
<NavigationContainer ref={navRef}>{/* screens with PlayerAnchor */}</NavigationContainer>
<VideoHost />
</MiniPlayerProvider><MiniPlayer> (Standalone)
Key props:
| Prop | Type | Default |
|------|------|---------|
| source | react-native-video source | required |
| visible | boolean | true |
| draggable | boolean | true |
| snapToEdge | boolean | true |
| swipeToClose | boolean | true |
| animation | spring \| timing \| fade \| scale \| slide \| bounce | spring |
| width / height | number | 168 / 94 |
| borderRadius | number | 12 |
| theme | theme name or object | provider theme |
| renderControls | (ctx) => ReactNode | default chrome |
| videoProps | passthrough to Video | — |
Events
onPlay · onPause · onClose · onExpand · onMinimize · onDragStart · onDrag · onDragEnd · onSnap · onFullscreen · onError · onProgress · onTap · onDoubleTap · onLongPress · swipe callbacks
Customization
<MiniPlayer
source={source}
width={180}
height={100}
borderRadius={16}
animation="bounce"
theme="light"
renderPlayIcon={() => <MyPlay />}
renderControls={(ctx) => <MyChrome {...ctx} />}
/>Continuous playback guarantee
Minimize / expand only animates width, height, translate, and radius. The Video component stays mounted with a stable session id, so seek position and decoder state persist.
Example
See example/ for:
- Basic mini player
- Custom UI
- Netflix-style
- YouTube-style
- Multiple videos
- Theme switching
Docs
Development
npm install
npm run typecheck
npm run buildLicense
MIT
