PraxisJS

DevTools Plugins

How to create and register custom plugins to extend the DevTools panel with new tabs.

DevTools Plugins

The DevTools panel is extensible — each tab is a plugin, including the three built-in ones. Add new tabs, replace existing ones, or strip the panel down to only what your project needs.


Built-in plugins

The default panels are exported individually so you can import and compose them:

import { SignalsPlugin, ComponentsPlugin, TimelinePlugin } from '@praxisjs/devtools'

Customizing which tabs appear

Pass a plugins array to DevTools.init() to control which tabs are shown:

import { DevTools, SignalsPlugin, TimelinePlugin } from '@praxisjs/devtools'

DevTools.init({
  plugins: [SignalsPlugin, TimelinePlugin]  // no Components tab
})

Registering a plugin after init

Use DevTools.registerPlugin() to add a plugin at any point after initialization. If a plugin with the same id is already registered, the call is a no-op.

import { DevTools } from '@praxisjs/devtools'

DevTools.registerPlugin(MyCustomPlugin)

Creating a custom plugin

A plugin is a plain object with four fields:

import type { DevtoolsPlugin, Registry } from '@praxisjs/devtools'
import { Component } from '@praxisjs/decorators'
import { StatefulComponent } from '@praxisjs/core'

@Component()
class NetworkTab extends StatefulComponent {
  @State() requests: NetworkRequest[] = []

  render() {
    return (
      <div>
        {() => this.requests.map(r => (
          <div>{r.method} {r.url} — {r.status}</div>
        ))}
      </div>
    )
  }
}

export const NetworkPlugin: DevtoolsPlugin = {
  id: 'network',       // unique ID — prevents duplicate registration
  label: 'Network',   // text shown on the tab

  // setup() runs once when the plugin is registered
  setup(registry: Registry) {
    registry.bus.on('timeline:push', (entry) => {
      // react to any timeline event
    })
  },

  // component is rendered inside the tab
  component: NetworkTab,
}

Interface:

interface DevtoolsPlugin {
  id: string
  label: string
  setup?: (registry: Registry) => void
  component: ComponentElement
}

Using the Registry

Registry is a singleton that holds all DevTools data. Inside setup() you receive it as an argument. Anywhere else, access it via DevTools.registry:

import { DevTools } from '@praxisjs/devtools'

const registry = DevTools.registry

// Read current data snapshots
registry.getSignals()     // SignalEntry[]
registry.getComponents()  // ComponentEntry[]
registry.getTimeline()    // TimelineEntry[]

// Subscribe to real-time events
registry.bus.on('signal:changed', ({ entry, oldValue }) => { /* ... */ })
registry.bus.on('component:render', (entry) => { /* ... */ })
registry.bus.on('timeline:push', (entry) => { /* ... */ })

Available events

EventPayload
signal:registeredSignalEntry
signal:changed{ entry: SignalEntry, oldValue }
component:registeredComponentEntry
component:renderComponentEntry
component:unmountComponentEntry
lifecycle{ componentId, name, hook }
timeline:pushTimelineEntry

On this page