# Components The architecture of the Video.js player is centered around components. The `Player` class and all classes representing player controls and other UI elements inherit from the `Component` class. This architecture makes it easy to construct the user interface of the Video.js player in a tree-like structure that mirrors the DOM. ## Table of Contents * [What is a Component?](#what-is-a-component) * [Creating a Component](#creating-a-component) * [Component Children](#component-children) * [Basic Example](#basic-example) * [Using Options](#using-options) * [Event Listening](#event-listening) * [Using on](#using-on) * [Using off](#using-off) * [Using one](#using-one) * [Using trigger](#using-trigger) * [Default Component Tree](#default-component-tree) * [Specific Component Details](#specific-component-details) * [Play Toggle](#play-toggle) * [Volume Panel](#volume-panel) * [Text Track Settings](#text-track-settings) * [Resize Manager](#resize-manager) ## What is a Component? A component is a JavaScript object that has the following features: * An associated DOM element, in almost all cases. * An association to a `Player` object. * The ability to manage any number of child components. * The ability to listen for and trigger events. * A lifecycle of initialization and disposal. For more specifics on the programmatic interface of a component, see [the component API docs][api]. ## Creating a Component Video.js components can be inherited and registered with Video.js to add new features and UI to the player. For a working example, [we have a JSBin](https://jsbin.com/vobacas/edit?html,css,js,output) demonstrating the creation of a component for displaying a title across the top of the player. In addition, there are a couple methods worth recognizing: * `videojs.getComponent(String name)`: Retrieves component constructors from Video.js. * `videojs.registerComponent(String name, Function Comp)`: Registers component constructors with Video.js. * `videojs.extend(Function component, Object properties)`: Provides prototype inheritance. Can be used to extend a component's constructor, returning a new constructor with the given properties. Creation: ```js // adding a button to the player var player = videojs('some-video-id'); var Button = videojs.getComponent('Button'); var button = new Button(player, { clickHandler: function(event) { videojs.log('Clicked'); } }); console.log(button.el()); ``` The above code will output ```html
Button
``` Adding the new button to the player ```js // adding a button to the player var player = videojs('some-video-id'); var button = player.addChild('button'); console.log(button.el()); // will have the same html result as the previous example ``` ## Component Children Again, refer to [the component API docs][api] for complete details on methods available for managing component structures. ### Basic Example When child component is added to a parent component, Video.js inserts the element of the child into the element of the parent. For example, adding a component like this: ```js // Add a "BigPlayButton" component to the player. Its element will be appended to the player's element. player.addChild('BigPlayButton'); ``` Results in a DOM that looks like this: ```html
``` Conversely, removing child components will remove the child component's element from the DOM: ```js player.removeChild('BigPlayButton'); ``` Results in a DOM that looks like this: ```html
``` ### Using Options Pass in options for child constructors and options for children of the child. ```js var player = videojs('some-vid-id'); var Component = videojs.getComponent('Component'); var myComponent = new Component(player); var myButton = myComponent.addChild('MyButton', { text: 'Press Me', buttonChildExample: { buttonChildOption: true } }); ``` Children can also be added via options when a component is initialized. > Note: Include a 'name' key which will be used if two child components of the same > type that need different options. ```js // MyComponent is from the above example var myComp = new MyComponent(player, { children: ['button', { name: 'button', someOtherOption: true }, { name: 'button', someOtherOption: false }] }); ``` ## Event Listening ### Using `on` ```js var player = videojs('some-player-id'); var Component = videojs.getComponent('Component'); var myComponent = new Component(player); var myFunc = function() { var myComponent = this; console.log('myFunc called'); }; myComponent.on('eventType', myFunc); myComponent.trigger('eventType'); // logs 'myFunc called' ``` The context of `myFunc` will be `myComponent` unless it is bound. You can add a listener to another element or component. ```js var otherComponent = new Component(player); // myComponent/myFunc is from the above example myComponent.on(otherComponent.el(), 'eventName', myFunc); myComponent.on(otherComponent, 'eventName', myFunc); otherComponent.trigger('eventName'); // logs 'myFunc called' twice ``` ### Using `off` ```js var player = videojs('some-player-id'); var Component = videojs.getComponent('Component'); var myComponent = new Component(player); var myFunc = function() { var myComponent = this; console.log('myFunc called'); }; myComponent.on('eventType', myFunc); myComponent.trigger('eventType'); // logs 'myFunc called' myComponent.off('eventType', myFunc); myComponent.trigger('eventType'); // does nothing ``` If myFunc gets excluded, _all_ listeners for the event type will get removed. If eventType gets excluded, _all_ listeners will get removed from the component. You can use `off` to remove listeners that get added to other elements or components using: `myComponent.on(otherComponent...` In this case both the event type and listener function are **REQUIRED**. ```js var otherComponent = new Component(player); // myComponent/myFunc is from the above example myComponent.on(otherComponent.el(), 'eventName', myFunc); myComponent.on(otherComponent, 'eventName', myFunc); otherComponent.trigger('eventName'); // logs 'myFunc called' twice myComponent.off(ootherComponent.el(), 'eventName', myFunc); myComponent.off(otherComponent, 'eventName', myFunc); otherComponent.trigger('eventName'); // does nothing ``` ### Using `one` ```js var player = videojs('some-player-id'); var Component = videojs.getComponent('Component'); var myComponent = new Component(player); var myFunc = function() { var myComponent = this; console.log('myFunc called'); }; myComponent.one('eventName', myFunc); myComponent.trigger('eventName'); // logs 'myFunc called' myComponent.trigger('eventName'); // does nothing ``` You can also add a listener to another element or component that will get triggered only once. ```js var otherComponent = new Component(player); // myComponent/myFunc is from the above example myComponent.one(otherComponent.el(), 'eventName', myFunc); myComponent.one(otherComponent, 'eventName', myFunc); otherComponent.trigger('eventName'); // logs 'myFunc called' twice otherComponent.trigger('eventName'); // does nothing ``` ### Using `trigger` ```js var player = videojs('some-player-id'); var Component = videojs.getComponent('Component'); var myComponent = new Component(player); var myFunc = function(data) { var myComponent = this; console.log('myFunc called'); console.log(data); }; myComponent.one('eventName', myFunc); myComponent.trigger('eventName'); // logs 'myFunc called' and 'undefined' myComponent.trigger({'type':'eventName'}); // logs 'myFunc called' and 'undefined' myComponent.trigger('eventName', {data: 'some data'}); // logs 'myFunc called' and "{data: 'some data'}" myComponent.trigger({'type':'eventName'}, {data: 'some data'}); // logs 'myFunc called' and "{data: 'some data'}" ``` ## Default Component Tree The default component structure of the Video.js player looks something like this: ```tree Player ├── MediaLoader (has no DOM element) ├── PosterImage ├── TextTrackDisplay ├── LoadingSpinner ├── BigPlayButton ├── LiveTracker (has no DOM element) ├─┬ ControlBar │ ├── PlayToggle │ ├── VolumePanel │ ├── CurrentTimeDisplay (hidden by default) │ ├── TimeDivider (hidden by default) │ ├── DurationDisplay (hidden by default) │ ├─┬ ProgressControl (hidden during live playback, except when liveui: true) │ │ └─┬ SeekBar │ │ ├── LoadProgressBar │ │ ├── MouseTimeDisplay │ │ └── PlayProgressBar │ ├── LiveDisplay (hidden during VOD playback) │ ├── SeekToLive (hidden during VOD playback) │ ├── RemainingTimeDisplay │ ├── CustomControlSpacer (has no UI) │ ├── PlaybackRateMenuButton (hidden, unless playback tech supports rate changes) │ ├── ChaptersButton (hidden, unless there are relevant tracks) │ ├── DescriptionsButton (hidden, unless there are relevant tracks) │ ├── SubtitlesButton (hidden, unless there are relevant tracks) │ ├── CaptionsButton (hidden, unless there are relevant tracks) │ ├── SubsCapsButton (hidden, unless there are relevant tracks) │ ├── AudioTrackButton (hidden, unless there are relevant tracks) │ ├── PictureInPictureToggle │ └── FullscreenToggle ├── ErrorDisplay (hidden, until there is an error) ├── TextTrackSettings └── ResizeManager (hidden) ``` ## Specific Component Details ### Play Toggle The `PlayToggle` has one option `replay` which can show or hide replay icon. This can be set by passing `{replay: false}` as the default behavior replay icon is shown after video end playback. Example of how to hide a replay icon ```js let player = videojs('myplayer', { controlBar: { playToggle: { replay: false } } }); ``` ### Volume Panel The `VolumePanel` includes the `MuteToggle` and the `VolumeControl` Components, which will be hidden if volume changes are not supported. There is one important option for the `VolumePanel` which can make your `VolumeControl` appear vertically over the `MuteToggle`. This can be set by passing `VolumePanel` `{inline: false}` as the default behavior is a horizontal `VolumeControl` with `{inline: true}`. Example of a vertical `VolumeControl` ```js let player = videojs('myplayer', { controlBar: { volumePanel: { inline: false } } }); ``` ### Text Track Settings The text track settings component is only available when using emulated text tracks. [api]: https://docs.videojs.com/Component.html ### Resize Manager This new component is in charge of triggering a `playerresize` event when the player size changed. It uses the ResizeObserver if available or a polyfill was provided. It has no element when using the ResizeObserver. If a ResizeObserver is not available, it will fallback to an iframe element and listen to its resize event via a debounced handler. A ResizeObserver polyfill can be passed in like so: ```js var player = videojs('myplayer', { resizeManager: { ResizeObserver: ResizeObserverPoylfill } }); ``` To force using the iframe fallback, pass in `null` as the `ResizeObserver`: ```js var player = videojs('myplayer', { resizeManager: { ResizeObserver: null } }); ``` The ResizeManager can also just be disabled like so: ```js var player = videojs('myplayer', { resizeManager: false }); ```