Extensions can add a chat interface to Superset by registering a trigger and a panel. The host owns the layout, open/close state, and display mode — the extension only needs to provide the UI components.
A chat registration consists of two React components:
| Component | Role |
|---|---|
| Trigger | Always-visible entry point (e.g., a floating button). Rendered in the bottom-right corner in floating mode, or as a fixed overlay in panel mode. |
| Panel | The chat UI itself (message list, input, etc.). Mounted by the host in the active display mode. |
The host supports two display modes, switchable by the user or the extension at runtime:
| Mode | Behavior |
|---|---|
floating | Panel floats above page content, anchored to the bottom-right corner. |
panel | Panel is docked to the right side of the application as a resizable sidebar, sitting beside the page content. |
The user's last selected mode and open/closed state are persisted across page reloads.
Call chat.registerChat from your extension's entry point with a descriptor, a trigger factory, and a panel factory:
import { chat } from '@apache-superset/core'; import ChatTrigger from './ChatTrigger'; import ChatPanel from './ChatPanel'; chat.registerChat( { id: 'my-org.my-chat', name: 'My Chat' }, ChatTrigger, ChatPanel, );
Only one chat registration is active at a time. If a second extension calls registerChat, it replaces the first and a warning is logged.
The trigger component is responsible for toggling the panel. Use chat.isOpen(), chat.open(), and chat.close() to control visibility:
import { chat } from '@apache-superset/core'; export default function ChatTrigger() { return ( <button onClick={() => (chat.isOpen() ? chat.close() : chat.open())}> 💬 </button> ); }
You can also subscribe to open/close events from any component:
useEffect(() => { const { dispose } = chat.onDidOpen(() => console.log('chat opened')); return dispose; }, []);
Call chat.setDisplayMode to switch between 'floating' and 'panel' modes. In your panel component, subscribe to onDidChangeDisplayMode to react to changes (including those triggered by the user):
import { useState, useEffect } from 'react'; import { chat } from '@apache-superset/core'; export default function ChatPanel() { const [mode, setMode] = useState(chat.getDisplayMode()); useEffect(() => { const { dispose } = chat.onDidChangeDisplayMode(m => setMode(m)); return dispose; }, []); return ( <div style={{ height: mode === 'panel' ? '100%' : '80vh' }}> <button onClick={() => chat.setDisplayMode(mode === 'panel' ? 'floating' : 'panel') } > {mode === 'panel' ? 'Float' : 'Dock'} </button> {/* message list and input */} </div> ); }
All methods are available on the chat namespace from @apache-superset/core:
| Method / Event | Description |
|---|---|
registerChat(descriptor, trigger, panel) | Register a chat extension. Returns a Disposable to unregister. |
open() | Open the chat panel. No-op if already open or no registration. |
close() | Close the chat panel. |
isOpen() | Returns true if the panel is currently open. |
getDisplayMode() | Returns the current display mode ('floating' or 'panel'). |
setDisplayMode(mode) | Switch between 'floating' and 'panel' mode. |
onDidOpen(listener) | Subscribe to panel open events. Returns a Disposable. |
onDidClose(listener) | Subscribe to panel close events. Returns a Disposable. |
onDidChangeDisplayMode(listener) | Subscribe to display mode changes. Returns a Disposable. |
onDidRegisterChat(listener) | Subscribe to registration events. |
onDidUnregisterChat(listener) | Subscribe to unregistration events. |
onDidResizePanel(listener) | Subscribe to panel resize events (panel mode only). Not all hosts provide a resizer — do not rely on this firing. Returns a Disposable. |