Summary
Custom video player with optional YouTube embed, skip controls, PiP, fullscreen, and compact control layout.Basic usage
HTML5 video with poster
YouTube embed from state
State & validation
Stored value
State string = direct video URL or YouTube/Vimeo URL.Validation rules
Built-in validation rejects malformed values, unsafe schemes, credentials in URLs and protocol-relative URLs. It checks the URL format; it does not verify that a remote file exists or that the browser can decode it.Configuration API
All methods acceptClosure unless noted.
ratio()
Supports standard aspect ratios. Invalid strings throw an InvalidArgumentException.
controlsLayout()
Use compact for the Video.js-style control layout. Players at least 512px wide show one bottom bar; narrower players place playback, volume, seeking and settings in a bottom bar, with PiP/fullscreen and remote playback in a separate upper corner group. Below 672px the inset is 8px; larger players use 12px. Time labels hide when their section becomes narrower than 256px. Click the right time value to switch between remaining time and total duration:
Real-world examples
Background video (Hero)
YouTube training video
Playground
/admin/flex-fields/video-field
See Playground for setup.
Related components
Player appearance
Performance
Settings, playback speed and quality
The settings menu is shown when it has at least two playback speeds or two direct-video sources to choose from. It slides between views, animates its dimensions and follows pointer or keyboard focus with a moving highlight. Reduced-motion preferences are respected.
Speed and quality lists accept at most 64 entries. Playback speeds must be finite and greater than zero. Quality sources must be safe HTTP(S) URLs or paths starting with a single
/. A quality switch preserves playback position and speed when the new source is ready. Use equivalent versions of the same recording. The source configured with src() is played initially; use the matching default entry for its initial quality label.
YouTube playback speeds are limited to the speeds supported by that video. Custom quality selection applies to direct video; Vimeo uses its embedded player controls. Casting, fullscreen, Picture-in-Picture and autoplay also depend on the browser, device and user permissions.
Keyboard and touch controls
Focus the player to use Space/K for play and pause, M for mute, F for fullscreen, I for Picture-in-Picture, arrow keys for five-second seeking or volume adjustment, and Escape to dismiss menus. Editable fields retain their normal keyboard behavior. In settings, Up/Down and Home/End move focus, Enter selects an option, and Escape closes the menu and returns focus to its trigger. Submenu navigation follows the page’s writing direction. On touch devices, double-tap the left or right side to skip byskipSeconds(); double-tap the center for fullscreen.
Size, corners and icons
Usesize('sm'), size('md') or size('lg') to change control dimensions. rounding() accepts the shared FLEX rounding values. Set fullWidth() to fill the available column and ratio() to preserve a chosen aspect ratio.
The custom player uses the original Video.js SVG icons, bundled locally and rendered inline. Volume has high, low and muted states; fullscreen, Picture-in-Picture and remote playback have separate entry and exit icons. No external icon request is needed.
Icon methods accept an icon identifier, enum, renderable icon or closure: playIcon(), pauseIcon(), volumeIcon(), volumeLowIcon(), muteIcon(), fullscreenIcon(), exitFullscreenIcon(), placeholderIcon(), settingsIcon(), speedIcon(), qualityIcon(), castIcon(), exitCastIcon(), airPlayIcon(), exitAirPlayIcon(), pictureInPictureIcon() and exitPictureInPictureIcon().
If you override volumeIcon(), castIcon() or airPlayIcon(), that icon also applies to the corresponding low-volume or connected state unless you supply a separate state icon:
Efficient frame previews
By default, native video previews seek a separate video decoder only when you move along the progress bar. For large videos, supply either a lightweight preview video or pre-generated thumbnail images. The player does not generate these files: prepare them in your media-processing workflow.Lightweight preview video
Use the same timeline as the original film, with a lower resolution and bitrate:Individual thumbnails
start is inclusive and end is exclusive, in seconds. Entries are sorted by
start time and must not overlap. Only the image for the hovered time loads:
Storyboard sprite
Several frames may share one image. Add the pixel coordinates of each frame:
The image cache holds at most eight images and eight megapixels in total. Images
that exceed the budget, fail to load, or leave gaps in the timeline fall back to
previewSource() or the original video. Keep storyboard sheets small; splitting
long timelines into multiple sheets limits decoded memory. A successful image
preview does not start the secondary video decoder. Frame images are cached,
and moving within the same frame interval does not repaint it.
For JSON custom fields, use preview_source and preview_thumbnails with the
same values. URL checks, interval ordering, overlap checks and crop validation
also apply to stored configuration. PHP closures are evaluated for the current
field; stored configuration contains data only.
Paused players do not run a playback clock. While custom controls are hidden,
the clock uses a 500ms timer; revealing them resumes animation-frame updates.
Hidden browser tabs and inactive form surfaces suspend that clock.