Skip to content

Settings Panel ​

Built-in ​

Enable setting: true and the corresponding options to install these four built-in items: flip, playbackRate, aspectRatio, subtitleOffset.

▶ Run Code
js
var art = new Artplayer({
    container: '.artplayer-app',
    url: '/assets/sample/video.mp4',
    setting: true,
    flip: true,
    playbackRate: true,
    aspectRatio: true,
    subtitleOffset: true,
});

Create - Button ​

PropertyTypeDescription
htmlString, Element, NumberThe DOM element
iconString, Element, NumberThe icon element
onClickFunctionThe click event
widthNumberThe list width
tooltipString, Element, NumberThe tooltip text
▶ Run Code
js
var art = new Artplayer({
    container: '.artplayer-app',
    url: '/assets/sample/video.mp4',
    setting: true,
    settings: [
        {
            html: 'Button',
            icon: '<img width="22" height="22" src="/assets/img/state.svg">',
            tooltip: 'tooltip',
            onClick(item, $dom, event) {
                console.info(item, $dom, event);
                return 'new tooltip';
            },
        },
    ],
});

Create - Selection List ​

PropertyTypeDescription
htmlString, Element, NumberThe DOM element
iconString, Element, NumberThe icon element
selectorArrayThe list of elements
onSelectFunctionThe click event
widthNumberThe list width
tooltipString, Element, NumberThe tooltip text
▶ Run Code
js
var art = new Artplayer({
    container: '.artplayer-app',
    url: '/assets/sample/video.mp4',
    setting: true,
    settings: [
        {
            html: 'Subtitle',
            width: 250,
            tooltip: 'Subtitle 01',
            selector: [
                {
                    default: true,
                    html: '<span style="color:red">Subtitle 01</span>',
                    url: '/assets/sample/subtitle.srt?id=1',
                },
                {
                    html: '<span style="color:yellow">Subtitle 02</span>',
                    url: '/assets/sample/subtitle.srt?id=2',
                },
            ],
            onSelect: function (item, $dom, event) {
                console.info(item, $dom, event);
                art.subtitle.url = item.url;
                return item.html;
            },
        },
        {
            html: 'Quality',
            width: 150,
            tooltip: '1080P',
            selector: [
                {
                    default: true,
                    html: '1080P',
                    url: '/assets/sample/video.mp4?id=1080',
                },
                {
                    html: '720P',
                    url: '/assets/sample/video.mp4?id=720',
                },
                {
                    html: '360P',
                    url: '/assets/sample/video.mp4?id=360',
                },
            ],
            onSelect: function (item, $dom, event) {
                console.info(item, $dom, event);
                art.switchQuality(item.url, item.html);
                return item.html;
            },
        },
    ],
});

Create - Nested List ​

▶ Run Code
js
var art = new Artplayer({
    container: '.artplayer-app',
    url: '/assets/sample/video.mp4',
    setting: true,
    settings: [
        {
            html: 'Multi-level',
            selector: [
                {
                    html: 'Setting 01',
                    width: 150,
                    selector: [
                        {
                            html: 'Setting 01 - 01',
                        },
                        {
                            html: 'Setting 01 - 02',
                        },
                    ],
                    onSelect: function (item, $dom, event) {
                        console.info(item, $dom, event);
                        return item.html;
                    },
                },
                {
                    html: 'Setting 02',
                    width: 150,
                    selector: [
                        {
                            html: 'Setting 02 - 01',
                        },
                        {
                            html: 'Setting 02 - 02',
                        },
                    ],
                    onSelect: function (item, $dom, event) {
                        console.info(item, $dom, event);
                        return item.html;
                    },
                },
            ],
        },
    ],
});

Create - Toggle Button ​

PropertyTypeDescription
htmlString, Element, NumberDOM element for the item
iconString, Element, NumberIcon for the item
switchBooleanDefault state of the button
onSwitchFunctionButton toggle event
tooltipString, Element, NumberTooltip text
▶ Run Code
js
var art = new Artplayer({
    container: '.artplayer-app',
    url: '/assets/sample/video.mp4',
    setting: true,
    settings: [
        {
            html: 'PIP Mode',
            tooltip: 'Close',
            icon: '<img width="22" height="22" src="/assets/img/state.svg">',
            switch: false,
            onSwitch: function (item, $dom, event) {
                console.info(item, $dom, event);
                const nextState = !item.switch;
                art.pip = nextState;
                item.tooltip = nextState ? 'Open' : 'Close';
                return nextState;
            },
        },
    ],
});

Create - Range Slider ​

PropertyTypeDescription
htmlString, Element, NumberDOM element for the item
iconString, Element, NumberIcon for the item
rangeArrayDefault state array
onRangeFunctionEvent triggered on completion
onChangeFunctionEvent triggered on change
tooltipString, Element, NumberTooltip text
js
const range = [5, 1, 10, 1];
const value = range[0];
const min = range[1];
const max = range[2];
const step = range[3];
▶ Run Code
js
var art = new Artplayer({
    container: '.artplayer-app',
    url: '/assets/sample/video.mp4',
    setting: true,
    settings: [
        {
            html: 'Slider',
            tooltip: '5x',
            icon: '<img width="22" height="22" src="/assets/img/state.svg">',
            range: [5, 1, 10, 1],
            onChange: function (item, $dom, event) {
                console.info(item, $dom, event);
                return item.range[0] + 'x';
            },
        },
    ],
});

Add ​

▶ Run Code
js
var art = new Artplayer({
    container: '.artplayer-app',
    url: '/assets/sample/video.mp4',
    setting: true,
});

art.setting.show = true;

art.setting.add({
    html: 'Slider',
    tooltip: '5x',
    icon: '<img width="22" height="22" src="/assets/img/state.svg">',
    range: [5, 1, 10, 1],
});

Remove ​

▶ Run Code
js
var art = new Artplayer({
    container: '.artplayer-app',
    url: '/assets/sample/video.mp4',
    setting: true,
    flip: true,
    settings: [
        {
            name: 'slider',
            html: 'Slider',
            tooltip: '5x',
            icon: '<img width="22" height="22" src="/assets/img/state.svg">',
            range: [5, 1, 10, 1],
        },
    ],
});

art.setting.show = true;

art.on('ready', () => {
    setTimeout(() => {
        // Delete the setting by name
        art.setting.remove('slider');
    }, 3000);
});

Update ​

▶ Run Code
js
var art = new Artplayer({
    container: '.artplayer-app',
    url: '/assets/sample/video.mp4',
    setting: true,
    settings: [
        {
            name: 'slider',
            html: 'Slider',
            tooltip: '5x',
            icon: '<img width="22" height="22" src="/assets/img/state.svg">',
            range: [5, 1, 10, 1],
        },
    ],
});

art.setting.show = true;

art.on('ready', () => {
    setTimeout(() => {
        // Remove the old interaction field before changing from range to switch
        delete art.setting.find('slider').range;
        // Update the setting by name
        art.setting.update({
            name: 'slider',
            html: 'PIP Mode',
            tooltip: 'Close',
            icon: '<img width="22" height="22" src="/assets/img/state.svg">',
            switch: false,
        });
    }, 3000);
});

Setting items and callback rules ​

Settings use a tree model, not the controls/layers node registry or beforeUnmount rules. Set setting: true to format/render the panel and install its regular events during construction. Each of the four built-in entries also requires its corresponding option. Their actual names are playback-rate, aspect-ratio, flip and subtitle-offset.

FieldActual purpose
nameUnique across the tree; omitted names become setting-N on the original object
html / icon / tooltipTrusted HTML strings, HTMLElement or numbers; rendering installs content accessors tied to nodes
widthRequested submenu width; zero/omitted uses SETTING_WIDTH, and actual dimensions are constrained by the player
valueCustom string/number data, not automatic media switching; historical falsy handling writes numeric zero as an empty data-value
defaultSelection flag; initial rendering does not replace the parent's tooltip from the selected entry
selectorNested items; a nonempty array opens a submenu
switchInitial state; onSwitch must return the next state, with no automatic inversion
range[value, min, max, step]; provide all four values, with omitted values and clamping governed by the native range input
mountedDeferred node-mount callback, not a synchronous construction callback
onClick / onSwitch / onRange / onChange / onSelectDistinct interaction callbacks described below

Falsy html/icon/tooltip during initial rendering use empty content or the default icon. Subsequent reads of content accessors return innerHTML strings. Assigning an HTMLElement moves it; strings are parsed as HTML and numbers become text. Do not insert untrusted content directly.

Each item has one interaction kind, selected by property presence: onClick takes precedence over range, then switch, then selector. This tests whether the property exists, not whether its value is truthy. When changing kinds, do not merely add a new field while retaining conflicting fields: replace with an independently named item or explicitly handle obsolete fields on the original object. Ordinary component disable/index/click/beforeUnmount are not setting availability, ordering or lifecycle APIs.

CallbackArguments and result
mounted(itemElement, item), with the player as this; scheduled with zero delay after insertion. Removal/replacement/destruction cancels pending work. The result is not UI content; Promise rejections produce a warning
onClick(item, itemElement, event); result becomes that item's tooltip
onSwitchSame arguments; result becomes switch. Without a callback, clicking does not toggle it
onChangeNative input event; when installed, writes the input value into item.range[0] before the callback, then writes its result into tooltip
onRangeNative change event; same update rules, for committed changes
onSelectDefined on the parent; receives the clicked leaf, its node and event. Selection/navigation to the parent list happens first, then the result becomes the parent tooltip

All interaction callbacks use the player as this and support Promise results. Only the latest operation for that target writes back while its items remain active. Results after removal, replacement or destruction are ignored. An omitted return does not preserve the old tooltip automatically: return the desired content or switch state. Errors warn without undoing an earlier selection or range[0] update. Mutating one range-array element does not synchronize the native input; assigning a complete new item.range array updates its properties. Without the corresponding onChange/onRange callback, native input changes do not synchronize range[0] through that callback path.

Manager methods and node ownership ​

  • find(name) returns the original item or null. add(item, option?) returns the supplied item; it appends to the root by default, or to an existing selector array passed as the second argument. Items gain names and accessors: do not freeze them or share them between two active players. Duplicate names, repeated object identity and cycles in one tree are rejected.
  • update(item) shallow-updates the existing named item and returns that original object; missing names call add. Rendered entries rebuild their nodes and release old listeners/subpanels, then return to the root list. Ordinary synchronous update failures attempt to restore the original item, nodes, listeners and navigation before rethrowing; this is not a transaction covering caller side effects.
  • remove(name) removes the item and descendants, cleans their listeners/subpanels, renders the root list and returns undefined. A missing name throws. Old DOM references no longer represent current nodes after removal/update; application-created resources remain application-owned.
  • show/toggle change visibility and emit setting. Setting show = true does not create a missing settings button or format an initially disabled panel; normally start with setting: true. resize() recomputes constrained dimensions when the panel is visible and has an active list and settings button.
  • traverse(callback, option?) visits actual objects in parent-before-child order, defaulting to the root. check(item) updates a formatted child's parent tooltip and default flags throughout the containing list and its descendants, then returns to the parent's containing list. No argument or a root item is a no-op.
  • render(option?) displays/caches a formatted list, defaulting to the root. format(option?, parent?, parents?, names?) validates/binds the tree and assigns the supplied list as the manager's option; it is not read-only validation. Usually let add/update manage this process.
  • createHeader/createItem are lower-level renderers requiring formatted items and cached panels. inactivate releases an item's subtree resources and subpanels without removing the item from its array. Use remove for complete removal rather than composing these internal steps.

Manager art references the player, name is setting, $parent is template.$setting and id generates names. option is the root array: construction combines built-ins and settings into a new array while retaining item identities. active is the current list or null; cache maps array identity to panel nodes. Each builtin read creates fresh entries from current options, not references to registered items. Use find for active entries and avoid mutating cache/active to bypass rendering.

Item metadataMeaning
$parentDirect parent item; undefined at root
$parentsList containing the direct parent, not the full ancestor chain; undefined at root
$optionArray containing this item
$events / $formattedManaged DOM cleanup array / established tree binding, not a currently-mounted flag
$item / $icon / $html / $tooltipRendered item/content nodes; unopened submenus may not have these yet
$switch / $rangeKind-specific switch node or native range input; do not retain obsolete references across updates

Tree metadata uses readonly nonenumerable accessors. DOM accessors are installed during rendering; retaining an item after removal does not mean its nodes are connected. Root declarations preserve historical inaccuracies: missing find results are typed undefined, add/update/remove are typed as returning the manager, and updateStyle(width?) does not actually exist. Use resize() and avoid chaining those methods based on old signatures. Root Setting describes an item, while the unpublished refactor's artplayer/runtime exports the Setting manager and generic SettingItem; these are different types.

TypeScript accurate-type example ​

ts
import Artplayer from 'artplayer/runtime';
import type { SettingItem } from 'artplayer/runtime';

const art = new Artplayer({ container: '#player', url: '/video.mp4', setting: true });
const option: SettingItem<typeof art> = {
    name: 'speed-label', html: 'Label', tooltip: 'Before',
    async onClick(item) { return 'After: ' + item.html; },
};
const added: SettingItem<typeof art> = art.setting.add(option);
const found: SettingItem<typeof art> | null = art.setting.find('speed-label');
if (found) art.setting.update({ name: found.name, html: 'New label' });
console.log(added === option);
art.setting.remove('speed-label');