@gfazioli/mantine-video
A customizable video player component for React built with Mantine. Compound API, headless useVideo hook, theme integration, and full Styles API support.
Installation
After installation import package styles at the root of your application:
You can import styles within a layer @layer mantine-video by importing @gfazioli/mantine-video/styles.layer.css file.
Usage
A video player built on the native HTML <video> element, themed with Mantine and composed of accessible building blocks. The default <Video /> renders a control bar with play / pause, timeline, time display, volume and fullscreen. Use the configurator below to explore the props in real time.
0:00 / 0:00
Basic example
The simplest usage: pass src, optionally poster and aspectRatio and you get a fully themed player out of the box. The control bar fades in on hover and auto-hides after a few seconds while playing.
0:00 / 0:00
Custom controls
The control bar is a compound component made of <Video.PlayButton />, <Video.Timeline />, <Video.TimeDisplay />, <Video.MuteButton />, <Video.SkipButton />, <Video.CaptionsButton />, <Video.PiPButton /> and <Video.FullscreenButton />. Pass controls={false} to opt out of the default layout and compose your own.
0:00 / -0:00
Variants
The component ships with four built-in variants. Each variant changes where and how the controls render relative to the video frame, but the API and sub-components stay identical — only variant changes.
overlay (default)
Controls float on top of the video at the bottom, with a soft dark gradient backdrop. They fade in on hover and auto-hide after a few seconds while playing, just like a typical YouTube-style player. This is the right default when the player is the focal point of the page.
0:00 / 0:00
minimal
The controls are placed below the video frame in the regular page flow. No overlay, no auto-hide, no gradient. The controls use the standard Mantine surface colors so they integrate naturally with the rest of the UI. Useful when the video is one element among many (a list, a card grid, a chat thread) and you want the controls to feel like part of the surrounding UI rather than a player chrome.
0:00 / 0:00
floating
Same overlay behavior as overlay, but the control bar is rendered inside a rounded floating card with a blurred backdrop, slightly inset from the video edges. A bit more "premium" / glass-morphism feel, good for hero videos and media-rich landing pages.
0:00 / 0:00
bordered
A hybrid: the container has a border and the controls are placed below the video (like minimal), but the whole player — frame + controls — is wrapped in a single bordered container. Best for embedding inside cards or wrapping a list of media items where you want a clearly delimited boundary.
0:00 / 0:00
Headless usage with useVideo
When the compound API is not flexible enough, use the useVideo hook to manage state and build a fully custom UI. The hook returns the video state and a complete set of actions and refs.
0.0s / 0.0s
Background video
The component can also be used as a section or full-page background — the kind of immersive hero you see on modern landing pages. The asBackground prop turns the player into an absolute-positioned, cover-cropped element ready to drop inside any positioned parent.
When asBackground is true the component:
- positions itself absolutely (
position: absolute; inset: 0) inside its parent - applies
object-fit: coverto the underlying<video>element - disables
controls,clickToToggle,shortcuts,doubleClickToFullscreenandautoHideControlsas defaults (you can still re-enable any of them explicitly) - renders a discreet floating mute button in the bottom-right corner, controllable via the
backgroundMuteButtonprop (defaulttrue)
For finer control, the standalone fit prop accepts 'cover' | 'contain' | 'fill' | 'none' | 'scale-down' and maps directly to CSS object-fit on the <video> element.
See it live
→ Open the fullscreen demo page → Open the homepage-style demo page. Both pages live outside the docs layout, full‑bleed.
Picture-in-Picture
The component supports the browser's native Picture-in-Picture API. When supported, the user can pop the video out into a floating, always-on-top window that survives tab switches and stays visible while they work in other apps.
How it works
Three things are wired up out of the box:
<Video.PiPButton />— an icon button in the default control bar. It callsrequestPictureInPicture()/exitPictureInPicture()under the hood and self-hides if the browser does not expose the standard API (notably Firefox, which still uses its own native button).- Keyboard shortcut — pressing P while the player has focus (and
shortcutsis enabled) toggles PiP. useVideohook — exposespipstate,canPiPcapability andrequestPiP/exitPiP/togglePiPactions so you can drive PiP from any UI.
Lifecycle callbacks
The Video component accepts onEnterPictureInPicture and onLeavePictureInPicture callbacks. Use them to react to the user popping the video in and out — for example to dim a sidebar, change the page layout or show a "playing in PiP" indicator.
0:00 / 0:00
Browser support
| Browser | Support |
|---|---|
| Chrome / Edge (desktop & Android) | Full standard API |
| Safari macOS 14+ | Full standard API |
| Safari iOS 14+ | Standard API, requires playsInline (default true) |
| Firefox | No standard API — uses its own button in the native controls. Video.PiPButton is hidden automatically. |
Limits of the underlying API
- Must be triggered by a user gesture (click, tap, key press). Programmatic auto-PiP is blocked by the browser.
- Only one PiP video at a time per browser. Entering PiP on another video closes the previous one.
- PiP window size is controlled by the user — the page cannot resize it.
- Videos with DRM-protected content may opt out of PiP.
Keyboard shortcuts
When shortcuts is enabled (default) and the player has focus:
| Key | Action |
|---|---|
| Space / K | Toggle play / pause |
| Arrow Left | Seek -5 s |
| Arrow Right | Seek +5 s |
| J | Seek -10 s |
| L | Seek +10 s |
| Arrow Up / Down | Volume + / - |
| M | Toggle mute |
| F | Toggle fullscreen |
| P | Toggle Picture-in-Picture |
Styles API
Video supports the full Mantine Styles API. Use classNames, styles, vars and unstyled to customize the root container, the underlying <video> element and every sub-component (controls, controlBar, playButton, timeline, timelineBuffered, timeDisplay, muteButton, fullscreenButton, pipButton, captionsButton, skipButton). Use the interactive playground below to inspect every selector and CSS variable.
0:00 / 0:00
Component Styles API
Hover over selectors to highlight corresponding elements