packages/docs/src/plugin/api-reference.md
::: warning The API is only available in Vue Devtools 6+ :::
Registers a devtools plugin. Describes the plugin and provides access to the devtools API.
setupDevtoolsPlugin (pluginDescriptor, setupFn)
The plugin descriptor is an object describing the devtools plugin to the Vue devtools user.
It has the following properties:
id: a unique id between all possible plugins. It's recommended to use a Reverse Domain Name notation, for example: org.vuejs.router, or the npm package name.app: the current application instance. The devtools is scoped to a specific application, so you have to specify on which application instance the devtools plugin is going to work.label: the label displayed to the user. It's recommended to use a user-friendly name from your plugin, for example: 'Vue Router'. Do not put 'devtools' or 'plugin' in the name, since the user will be seeing this devtools plugin while using your Vue plugin already.packageName (optional): The npm package name associated with the devtools plugin, for example 'vue-router'.homepage (optional): URL to your documentation.logo (optional): URL to a logo of your Vue plugin.componentStateTypes (optional): an array of custom component state section names you are going to add to the Component inspector. If you add new state to the component inspector, you should declare their sections here so the devtools can display the plugin icon.disableAppScope (optional): if set to true, the hooks registered with this plugin will not be scoped to the associated app. In that case, you might need to use the app payload property to check what the current app is inside each hook.disablePluginScope (optional): if set to true, the hooks registered with this plugin will not be scoped to the current plugin. In that case, you might need to use the pluginId payload property (depending on the hook) to check what the related plugin is inside each hook.enableEarlyProxy (optional): if set to true, the plugin will run even if the Vue devtools are not connected yet using a proxy of the Plugin API and a buffer queue. This is useful if you need to add timeline events before the user opens the devtools.settings (optional): an object describing the plugin settings. Learn more about plugin settings here.Example:
const stateType = 'routing properties'
setupDevtoolsPlugin({
id: 'org.vuejs.router',
app,
label: 'Vue Router',
packageName: 'vue-router',
homepage: 'https://router.vuejs.org/',
logo: 'https://vuejs.org/images/icons/favicon-96x96.png',
componentStateTypes: [
stateType
]
}, (api) => {
// Use the API here
})
Use this hook to add tags in the component tree.
The payload argument:
app: app instance currently active in the devtoolscomponentInstance: the current component instance data in the treetreeNode: the tree node that will be sent to the devtoolsfilter: the current value of the seach input above the tree in the component inspectorExample:
api.on.visitComponentTree((payload) => {
const node = payload.treeNode
if (node.name === 'MyApp') {
node.tags.push({
label: 'root',
textColor: 0x000000,
backgroundColor: 0xFF984F
})
}
else {
node.tags.push({
label: 'test',
textColor: 0xFFAAAA,
backgroundColor: 0xFFEEEE,
tooltip: `It's a test!`
})
}
})
Use this hook to add new information to the state of the selected component.
The payload argument:
app: app instance currently active in the devtoolscomponentInstance: the current component instance data in the treeinstanceData: the state that will be sent to the devtoolsTo add new state, you can push new fields into the instanceData.state array:
type: name of the section under which the field will appearkey: name of the fieldvalue: value of the fieldeditable (optional): boolean to enable editionBy default, the devtools will display your field depending on whether it's an object, an array, etc. You can customize the field display by putting a { _custom: {} } object to the value.
The _custom object has the following properties:
type: Displays the type of the value. Examples: 'router', 'component', 'service'...display: Text displayed instead of the value. Example: '5 minutes'tooltip: Tooltip when hovering the value text (display)value: Actual valueabstract: No value is displayed. Useful for indexes. For example, Set objects have abstract index child fields: 0, 1...readOnly: mark this value has not editablefields: an object of configure immediate child fields
abstractactions: an array of buttons to add to the field
icon: material icon identifiertooltip: button tooltipaction: function to be executedWhen you add new sections with the type property, you should declare them in the componentStateTypes array in the plugin descriptor when you call the setupDevtoolsPlugin.
Example:
api.on.inspectComponent((payload) => {
if (payload.instanceData) {
payload.instanceData.state.push({
type: stateType,
key: 'foo',
value: 'bar'
})
payload.instanceData.state.push({
type: stateType,
key: 'time',
value: {
_custom: {
type: null,
readOnly: true,
display: `${time}s`,
tooltip: 'Elapsed time',
value: time,
actions: [
{
icon: 'input',
tooltip: 'Log to console',
action: () => console.log('current time:', time)
}
]
}
}
})
}
})
If you mark a field as editable: true, you should also use this hook to apply the new value sent by the devtools.
You have to put a condition in the callback to target only your field type:
api.on.editComponentState((payload) => {
if (payload.type === stateType) {
// Edit logic here
}
})
The payload argument:
app: app instance currently active in the devtoolstype: the current field typepath: an array of string that represents the property edited by the user. For example, if the user edits the myObj.myProp.hello property, the path will be ['myObj', 'myProp', 'hello'].state: object describing the edit with those properties:
value: new valuenewKey: string that is set if the key of the value changed, usually when it's in an objectremove: if true, the value should be removed from the object or arrayset: an helper function that makes it easy to apply the edit on a state objectExample:
api.on.editComponentState((payload) => {
if (payload.type === stateType) {
payload.set(myState)
}
})
Here is a full example of an editable custom component field:
const myState = {
foo: 'bar'
}
api.on.inspectComponent((payload) => {
if (payload.instanceData) {
payload.instanceData.state.push({
type: stateType,
key: 'foo',
value: myState.foo,
editable: true
})
}
})
api.on.editComponentState((payload) => {
if (payload.type === stateType) {
payload.set(myState)
}
})
As you can see, you should use an object to hold the field value so that it can be assigned to.
If your state has changed, you can tell the devtools to refresh the selected component state with the notifyComponentUpdate method:
setInterval(() => {
api.notifyComponentUpdate()
}, 5000)
You can also pass a specific component instance:
api.notifyComponentUpdate(vm)
Custom inspectors are useful to display debugging information about your library using an inspectable tree.
This function registers a new custom inspector.
The options are:
id: unique custom inspector idlabel: label displayed in the Inspector sub menuicon (optional): Material icon code, for example 'star'treeFilterPlaceholder (optional): placeholder of the filter input above the treestateFilterPlaceholder (optional): placeholder of the filter input in the state inspectornoSelectionText (optional): text displayed in the inspector pane when no node is selectedactions: an array of buttons to add to the header of the inspector
icon: material icon identifiertooltip: button tooltipaction: function to be executednodeActions: an array of buttons to add to the selected node pane
icon: material icon identifiertooltip: button tooltipaction: function to be executedExample:
const INSPECTOR_ID = 'test-inspector'
api.addInspector({
id: INSPECTOR_ID,
label: 'Test inspector',
icon: 'tab_unselected',
treeFilterPlaceholder: 'Search for test...',
actions: [
{
icon: 'star',
tooltip: 'Test custom action',
action: () => console.log('Meow! 🐱')
}
],
nodeActions: [
{
icon: 'star',
tooltip: 'Test node custom action',
action: nodeId => console.log('Node action:', nodeId)
}
]
})
::: tip
It's recommended to use a variable to put the id, so that you can reuse it afterwards.
:::
This hook is called when the devtools wants to load the tree of any custom inspector.
You have to put a condition in the callback to target only your inspector:
api.on.getInspectorTree((payload) => {
if (payload.inspectorId === 'test-inspector') {
// Your logic here
}
})
The payload argument:
app: app instance currently active in the devtoolsinspectorId: id of the current custom inspectorfilter: string of the user input in the search fieldrootNodes: array of root nodes of the tree you want to display in the devtoolsEach node can have those properties:
id: a unique node idlabel: the text displayed in the treechildren (optional): an array of child nodestags (optional): an array of tag objects:
label: text displayed in the tagtextColor: text color, for example: 0x000000 for blackbackgroundColor: background color, for example: 0xffffff for whitetooltip (optional): HTML for a tooltip over the tagExample:
api.on.getInspectorTree((payload) => {
if (payload.inspectorId === 'test-inspector') {
payload.rootNodes = [
{
id: 'root',
label: `Root (${time})`,
children: [
{
id: 'child',
label: `Child ${payload.filter}`,
tags: [
{
label: 'active',
textColor: 0x000000,
backgroundColor: 0xFF984F
},
{
label: 'test',
textColor: 0xFFFFFF,
backgroundColor: 0x000000
}
]
}
]
}
]
}
})
This hook is called when the devtools needs to load the state for the currently selected node in a custom inspector.
You have to put a condition in the callback to target only your inspector:
api.on.getInspectorState((payload) => {
if (payload.inspectorId === 'test-inspector') {
// Your logic here
}
})
The payload argument:
app: app instance currently active in the devtoolsinspectorId: id of the current custom inspectornodeId: id of the currently selected nodestate: state sent to the devtoolsThe state is an object, which keys are the section names in the state inspector, and the value is an array of fields:
payload.state = {
'section 1': [
// fields
],
'section 2': [
// fields
]
}
Each field is an object with:
type: name of the section under which the field will appearkey: name of the fieldvalue: value of the fieldeditable (optional): boolean to enable editionYou can also use a Custom value.
Example:
api.on.getInspectorState((payload) => {
if (payload.inspectorId === 'test-inspector') {
if (payload.nodeId === 'root') {
payload.state = {
'root info': [
{
key: 'foo',
value: myState.foo,
editable: true
},
{
key: 'time',
value: time
}
]
}
}
else {
payload.state = {
'child info': [
{
key: 'answer',
value: {
_custom: {
display: '42!!!',
value: 42,
tooltip: 'The answer'
}
}
}
]
}
}
}
})
If you mark a field as editable: true, you should also use this hook to apply the new value sent by the devtools.
You have to put a condition in the callback to target only your inspector:
api.on.editInspectorState((payload) => {
if (payload.inspectorId === 'test-inspector') {
// Edit logic here
}
})
The payload argument:
app: app instance currently active in the devtoolsinspectorId: id of the current custom inspectornodeId: id of the currently selected nodetype: the current field typepath: an array of string that represents the property edited by the user. For example, if the user edits the myObj.myProp.hello property, the path will be ['myObj', 'myProp', 'hello'].state: object describing the edit with those properties:
value: new valuenewKey: string that is set if the key of the value changed, usually when it's in an objectremove: if true, the value should be removed from the object or arrayset: an helper function that makes it easy to apply the edit on a state objectExample:
api.on.editInspectorState((payload) => {
if (payload.inspectorId === 'test-inspector') {
if (payload.nodeId === 'root') {
payload.set(myState)
}
}
})
If you need to update the tree to the user, call this function to ask for a refresh.
Example:
setInterval(() => {
api.sendInspectorTree('test-inspector')
}, 5000)
If you need to update the currently selected node state to the user, call this function to ask for a refresh.
Example:
setInterval(() => {
api.sendInspectorState('test-inspector')
}, 5000)
Select a specific node in the inspector tree. The arguments are:
inspectorId: the id of your inspectornodeId: the id of the node to be selectedExample:
api.selectInspectorNode('test-inspector', 'some-node-id')
Returns the current time with the maximum available precision.
api.now()
Register a new timeline layer with this method. The options are:
id: unique id of the layer. It's recommended to use a variable to store it.label: text displayed in the layer listcolor: color of the layer background and event graphicsskipScreenshots (optional): don't trigger a screenshot for the layer eventsgroupsOnly (optional): only display groups of events (they will be drawn as rectangles)ignoreNoDurationGroups (optional): skip groups with no duration (useful when groupsOnly is true)Example:
api.addTimelineLayer({
id: 'test-layer',
label: 'Test layer',
color: 0x92A2BF
})
Use this function to send a new event on the timeline.
layerId: id of the layerevent: event object
time: time in millisecond when the event happeneddata: state displayed when selecting the eventtitle (optional): text displayed in the event listsubtitle (optional): secondary text displayed in the event listlogType (optional): either 'default', 'warning' or 'error'meta (optional): object where you can store metadata about the object that will not be displayed when it's selectedgroupId (optional): id used to group multiple event togetherExample:
api.addTimelineEvent({
layerId: 'test-layer',
event: {
time: api.now(),
data: {
info: 'window.keyup',
key: event.key
},
groupId: event.key,
title: 'Group test',
meta: {
foo: 'bar'
}
}
})
This hook is called when a timline event is selected. It's useful if you want to send additional information to the devtools in a lazy way.
You have to put a condition in the callback to target only your timeline layer:
api.on.inspectTimelineEvent((payload) => {
if (payload.layerId === 'test-layer') {
// Your logic here
}
})
Example:
api.on.inspectTimelineEvent((payload) => {
if (payload.layerId === 'test-layer') {
// Async operation example
return new Promise((resolve) => {
setTimeout(() => {
payload.data = {
...payload.data,
hey: 'hello'
}
resolve()
}, 1000)
})
}
})
This hook is called when the timeline is cleared by the user. Note that clearing the timeline affects all apps and layers simultaneously.
api.on.timelineCleared(() => {
console.log('timeline is cleared!')
})
Plugin settings allow the user to customize the plugin behavior. Learn more about plugin settings here.
Get the current plugin settings.
Example:
api.getSettings()
Hook called when the user changes the plugin settings.
Payload properties:
key: settings itemnewValue: new value for the changed settingsoldValue: its old value (deep clone)settings: the whole current settings state object// Plugin settings change
api.on.setPluginSettings((payload) => {
console.log(
'plugin settings changed',
payload.settings,
// Info about the change
payload.key,
payload.newValue,
payload.oldValue
)
})
Component instances on the Vue app.
app: the target Vue app instanceExample:
let componentInstances = []
api.on.getInspectorTree(async (payload) => {
if (payload.inspectorId === 'test-inspector') { // e.g. custom inspector
componentInstances = await api.getComponentInstances(app)
for (const instance of instances) {
payload.rootNodes.push({
id: instance.uid.toString(),
label: `Component ${instance.uid}`
})
}
// something todo ...
}
})
Computes the component bounds on the page.
Example:
api.on.inspectComponent(async (payload) => {
if (payload.instanceData) {
const bounds = await api.getComponentBounds(payload.componentInstance)
payload.instanceData.state.push({
type: stateType,
key: 'bounds',
value: bounds
? {
left: bounds.left,
top: bounds.top,
width: bounds.width,
height: bounds.height
}
: null
})
}
})
Retrieves the component name.
Example:
api.on.inspectComponent(async (payload) => {
if (payload.instanceData) {
const componentName = await api.getComponentName(payload.componentInstance)
payload.instanceData.state.push({
type: stateType,
key: 'component name',
value: componentName
})
}
})
Highlight the element of the component.
instance: the target component instanceExample:
const componentInstances = [] // keeped component instance of the Vue app (e.g. `getComponentInstances`)
api.on.getInspectorState((payload) => {
if (payload.inspectorId === 'test-inspector') { // e.g. custom inspector
// find component instance from custom inspector node
const instance = componentInstances.find(instance => instance.uid.toString() === payload.nodeId)
if (instance) {
api.highlightElement(instance)
}
// something todo ...
}
})
Unhighlight the element.
instance: the target component instanceExample:
const componentInstances = [] // keeped component instance of the Vue app (e.g. `getComponentInstances`)
api.on.getInspectorState((payload) => {
if (payload.inspectorId === 'test-inspector') { // e.g. custom inspector
// find component instance from custom inspector node
const instance = componentInstances.find(instance => instance.uid.toString() === payload.nodeId)
if (instance) {
api.unhighlightElement(instance)
}
// something todo ...
}
})