Media@knitui/media
Video
A hybrid, cross-platform video player. On web it drives the real browser <video> element; on React Native it drives expo-video. Both share one controller contract and the same kit-built control chrome.
import { Video } from "@knitui/media";Playground
Loading playground…
<Video
source="https://media.w3.org/2010/05/sintel/trailer.mp4"
contentFit="contain"
size="md"
controls
autoHide
loop={false}
muted={false}
aspectRatio={1.7777777777777777}
/>Examples
Basic
Loading example…
Auto Play Muted
Loading example…
Content Fit Cover
Loading example…
Sizes
Control sizing across the shared kit scale — the chrome's buttons, icons, and scrubber all step together off the canonical controlMetrics/icon ladders (the same scale Button/ActionIcon use), not a media-local copy.
Loading example…
Native Platform Controls
Loading example…
Custom Control Bar
Compose a custom control bar from the exported parts.
Loading example…
Captions
Loading example…
Custom Styled Captions
Because captions ride the kit overlay (not the platform's built-in subtitle renderer), their typography is fully stylable via the captions / captionText style slots — font, size, color, weight, background.
Loading example…
Keyboard Shortcuts
Keyboard shortcuts (focus the player first): Space/k play·pause, ←/→ seek, ↑/↓ volume, m mute, f fullscreen, p PiP, 0–9 jump, </> speed.
Loading example…
Persistent Controls
Always-visible controls (no auto-hide).
Loading example…
Styles
Per-slot styles overrides (Pillar B).
Loading example…
Swap Source
Two players sharing nothing but the contract — swap the source at runtime.
Loading example…
Two Players
Two players sharing ONE shared video engine (the default singleton). The single <video> teleports into whichever player you press play on; the other shows its poster and pauses. Returning to the first resumes from where you left off — and there is only ever ONE <video> element in the DOM.
Loading example…
Now Playing
Now-playing / lock-screen controls with a cover preview. nowPlaying folds the title/artist/artwork into the source metadata and flips expo-video's showNowPlayingNotification + staysActiveInBackground, so the OS shows a media notification with the artwork as the cover and playback keeps going in the background. Native-only — surfacing it on a device build also needs the expo-video config plugin's supportsBackgroundPlayback: true. (No-op on web; the story still renders a normal player there.)
Loading example…
Props
| Prop | Type | Default | Description |
|---|---|---|---|
source required | string | number | VideoSourceObject | null | https://media.w3.org/2010/05/sintel/trailer.mp4 | The media to play. |
allowsPictureInPicture | boolean | undefined | — | Allow Picture-in-Picture. Default `true`. |
artist | string | undefined | — | Now-playing artist / secondary text under the title. |
artwork | string | undefined | — | Now-playing artwork (cover) image URL. |
aspectRatio | number | undefined | — | Fixed aspect ratio for the frame (e.g. `16 / 9`). |
autoHide | number | boolean | undefined | true | Auto-hide the chrome during playback. `true` uses the default delay, `false` keeps it always visible, a number sets the delay in ms. |
autoPlay | boolean | undefined | — | Begin playback as soon as the source is ready. |
contentFit | VideoContentFit | undefinedcontain · cover · fill | contain | How the frame is scaled in the container. Default `'contain'`. |
controls | ReactNode | true | The control chrome. `true` (default) renders the built-in control bar; `false` renders no chrome; a node renders custom chrome inside the context (compose `Video.*` parts). |
controlsOffset | number | SpaceTokens | undefined | — | Inset of the control bar from the frame edges. |
doubleClickToFullscreen | boolean | undefined | — | Web: double-click/tap the video to toggle fullscreen. Default `true`. |
getController | ((controller: VideoController) => void) | undefined | — | Receives the controller once ready. |
height | number | Animated.AnimatedNode | GetThemeValueForKey<"height"> | null | undefined | — | |
id | string | undefined | — | Stable identity for the shared-engine registry. Defaults to a generated id (each `<Video>` is its own player); pass an explicit `id` to make two mounts address the SAME shared-engine slot. |
keyboard | boolean | undefined | — | Enable keyboard shortcuts (space, arrows, m, f, …). Default `true`. |
label | string | undefined | — | Accessible label for the player region. Default `"Video player"`. |
loop | boolean | undefined | false | Replay automatically on end. |
muted | boolean | undefined | false | Start muted (required by browsers for unattended autoplay). |
nativeControls | boolean | undefined | — | Use the platform's own native controls instead of the kit chrome. |
nowPlaying | boolean | VideoMetadata | undefined | — | Enable the OS now-playing notification + lock-screen controls (native; no-op on web). `true` derives the displayed metadata from `title`/`artist`/`artwork`; an object supplies it explicitly. Surfacing it on a device build also requires the `expo-video` config plugin's `supportsBackgroundPlayback: true`. |
onEnded | (() => void) | undefined | — | |
onError | ((error: VideoError) => void) | undefined | — | |
onPlayingChange | ((playing: boolean) => void) | undefined | — | |
onReady | (() => void) | undefined | — | Fired once the player first becomes ready to play. |
onStatusChange | ((status: VideoStatus, error: VideoError | null) => void) | undefined | — | |
onTimeUpdate | ((currentTime: number) => void) | undefined | — | |
playbackRate | number | undefined | — | Initial playback rate. |
poster | string | undefined | — | Poster image shown before playback (placeholder while the player is idle). |
showBigPlayButton | boolean | undefined | — | Show the centered big play button while paused. Default `true`. |
size system | "xxs" | "xs" | "sm" | "md" | "lg" | "xl" | "xxl" | undefinedxxs · xs · sm · md · lg · xl · xxl | md | Control sizing scale. Default `'md'`. |
styles system | SlotStyles<VideoStyles> | undefined | — | Per-slot style overrides. |
testID | string | undefined | — | |
textTracks | VideoTextTrack[] | undefined | — | External (sidecar) caption files. The controller fetches, parses, and renders them with the kit's own overlay on every platform. |
timeUpdateInterval | number | undefined | — | Seconds the controller waits between `timeUpdate` emissions (native). |
title | string | undefined | — | Now-playing title (used for the OS lock-screen / now-playing notification). |
updateInterval | number | undefined | — | Status / `timeUpdate` interval, ms (native). The unified name. |
volume | number | undefined | — | Initial volume, 0..1. |
width | number | GetThemeValueForKey<"width"> | Animated.AnimatedNode | null | undefined | — | Frame style props (width/height/borderRadius…). |
Style slots
Every part of Video can be styled through the styles prop. Explicit props on the component always win over slot styles.
| Slot | Usage |
|---|---|
bigPlay | styles={{ bigPlay: { … } }} |
buffering | styles={{ buffering: { … } }} |
captionText | styles={{ captionText: { … } }} |
captions | styles={{ captions: { … } }} |
controlBar | styles={{ controlBar: { … } }} |
root | styles={{ root: { … } }} |
scrim | styles={{ scrim: { … } }} |
surface | styles={{ surface: { … } }} |