9.8 KiB
Plugin Button Registration API
An easy way to register plugin buttons in various UI locations with positioning and grouping support.
Example Plugins
- example-button-plugin/ - Simple examples showing basic usage patterns
- example-showcase-plugin/ - Complete demonstration of ALL 11 locations ⭐
UI Locations
Buttons render in two visual styles depending on location — nav list rows (icon + label, full width) or icon buttons (compact, toolbar/header style).
Nav List Rows
These render as full-width list entries matching the style of built-in items like "Create Room" and "Message Search":
| Location | Where it appears |
|---|---|
channel-list |
Space channel list, below Lobby and Message Search |
home-section |
Home panel, inside the Rooms category above the room list |
direct-messages |
Direct Messages panel, below "Create Chat" and above the CHATS dropdown |
Icon Buttons
These render as compact icon buttons inline with other toolbar/header controls:
| Location | Where it appears |
|---|---|
text-composer-toolbar |
Message composer toolbar (alongside emoji, sticker buttons) |
composer-actions |
Left side of the composer, beside the + attach button |
room-header |
Top room header bar, before the ⋮ menu button |
room-menu |
Room ⋮ dropdown menu |
message-actions |
Message hover action bar |
user-menu |
Right-click popup on the user avatar |
search-notification-section |
Notifications page header (right side) |
sidebar-actions |
Left sidebar — appears in two places: above the Explore Servers icon, and above the Search icon in the sticky bottom section |
💡 Tip: Install the example-showcase-plugin to see exactly where each location appears in the UI!
Basic Usage
Simple Button
module.exports = {
name: 'my-plugin',
version: '1.0.0',
onLoad: (context) => {
context.ui.registerButton({
id: 'my-button',
location: 'text-composer-toolbar',
label: 'My Action',
icon: '🎨',
onClick: () => {
context.log('Button clicked!');
}
});
},
onUnload: () => {
// Buttons are automatically cleaned up on plugin unload
}
};
Positioning
Before/After Positioning
Place your button before or after existing buttons:
context.ui.registerButton({
id: 'my-button',
location: 'text-composer-toolbar',
label: 'My Action',
icon: '✨',
position: {
before: 'emoji-picker-button', // Place before emoji picker
// OR
after: 'sticker-button' // Place after sticker button
}
});
Grouping Buttons
Group related buttons together:
context.ui.registerButton({
id: 'action-1',
location: 'text-composer-toolbar',
label: 'Action 1',
icon: '1️⃣',
position: {
group: 'my-plugin-tools',
order: 1 // Lower numbers appear first
}
});
context.ui.registerButton({
id: 'action-2',
location: 'text-composer-toolbar',
label: 'Action 2',
icon: '2️⃣',
position: {
group: 'my-plugin-tools',
order: 2
}
});
Combined Positioning and Grouping
Place a group before/after other elements:
context.ui.registerButton({
id: 'tool-1',
location: 'text-composer-toolbar',
label: 'Tool 1',
icon: '🔧',
position: {
group: 'my-tools',
after: 'emoji-picker-button',
order: 1
}
});
context.ui.registerButton({
id: 'tool-2',
location: 'text-composer-toolbar',
label: 'Tool 2',
icon: '🔨',
position: {
group: 'my-tools',
order: 2
}
});
Complete Example
module.exports = {
name: 'custom-tools',
version: '1.0.0',
onLoad: (context) => {
// Nav list row — appears below "Create Chat" in the DMs panel
context.ui.registerButton({
id: 'dm-favorites',
location: 'direct-messages',
label: 'Favourites',
icon: '⭐',
onClick: () => context.log('Favourites clicked!')
});
// Nav list row — appears in the space channel list
context.ui.registerButton({
id: 'quick-access',
location: 'channel-list',
label: 'Quick Access',
icon: '⚡',
onClick: () => context.log('Quick access clicked!')
});
// Icon button — appears in the message composer toolbar
context.ui.registerButton({
id: 'format-bold',
location: 'text-composer-toolbar',
label: 'Bold',
icon: '𝐁',
position: {
group: 'custom-formatting',
order: 1
},
onClick: () => context.log('Bold clicked!')
});
// Icon button — appears in the room header
context.ui.registerButton({
id: 'special-search',
location: 'room-header',
label: 'Special Search',
icon: '🔍',
position: { after: 'search-button' },
onClick: () => context.log('Special search clicked!')
});
// Sidebar icon — appears above Explore and above Search
context.ui.registerButton({
id: 'plugin-panel',
location: 'sidebar-actions',
label: 'Plugin Panel',
icon: '🧩',
onClick: () => context.log('Plugin panel clicked!')
});
},
onUnload: () => {
// All registered buttons are automatically cleaned up
}
};
Unregistering Buttons
Buttons are automatically unregistered when the plugin is unloaded. To manually unregister:
context.ui.unregisterButton('my-button-id');
TypeScript Types
import type { UIButtonDefinition, UIButtonPosition, UILocation } from '@paarrot/plugin-manager';
const button: UIButtonDefinition = {
id: 'my-button',
location: 'text-composer-toolbar',
label: 'My Action',
icon: '🎨',
position: {
group: 'my-tools',
after: 'emoji-picker',
order: 1
},
onClick: () => console.log('Clicked!')
};
Basic Usage
Simple Button
module.exports = {
name: 'my-plugin',
version: '1.0.0',
onLoad: (context) => {
context.ui.registerButton({
id: 'my-button',
location: 'text-composer-toolbar',
label: 'My Action',
icon: '🎨',
onClick: () => {
context.log('Button clicked!');
}
});
},
onUnload: () => {
// Buttons are automatically cleaned up on plugin unload
}
};
Positioning
Before/After Positioning
Place your button before or after existing buttons:
context.ui.registerButton({
id: 'my-button',
location: 'text-composer-toolbar',
label: 'My Action',
icon: '✨',
position: {
before: 'emoji-picker-button', // Place before emoji picker
// OR
after: 'sticker-button' // Place after sticker button
}
});
Grouping Buttons
Group related buttons together:
context.ui.registerButton({
id: 'action-1',
location: 'text-composer-toolbar',
label: 'Action 1',
icon: '1️⃣',
position: {
group: 'my-plugin-tools',
order: 1 // Lower numbers appear first
}
});
context.ui.registerButton({
id: 'action-2',
location: 'text-composer-toolbar',
label: 'Action 2',
icon: '2️⃣',
position: {
group: 'my-plugin-tools',
order: 2
}
});
Combined Positioning and Grouping
Place a group before/after other elements:
context.ui.registerButton({
id: 'tool-1',
location: 'text-composer-toolbar',
label: 'Tool 1',
icon: '🔧',
position: {
group: 'my-tools',
after: 'emoji-picker-button',
order: 1
}
});
context.ui.registerButton({
id: 'tool-2',
location: 'text-composer-toolbar',
label: 'Tool 2',
icon: '🔨',
position: {
group: 'my-tools',
order: 2
}
});
Complete Example
module.exports = {
name: 'custom-tools',
version: '1.0.0',
onLoad: (context) => {
// Nav list row — appears below "Create Chat" in the DMs panel
context.ui.registerButton({
id: 'dm-favorites',
location: 'direct-messages',
label: 'Favourites',
icon: '⭐',
onClick: () => context.log('Favourites clicked!')
});
// Nav list row — appears in the space channel list
context.ui.registerButton({
id: 'quick-access',
location: 'channel-list',
label: 'Quick Access',
icon: '⚡',
onClick: () => context.log('Quick access clicked!')
});
// Icon button — appears in the message composer toolbar
context.ui.registerButton({
id: 'format-bold',
location: 'text-composer-toolbar',
label: 'Bold',
icon: '𝐁',
position: {
group: 'custom-formatting',
order: 1
},
onClick: () => context.log('Bold clicked!')
});
// Icon button — appears in the room header
context.ui.registerButton({
id: 'special-search',
location: 'room-header',
label: 'Special Search',
icon: '🔍',
position: { after: 'search-button' },
onClick: () => context.log('Special search clicked!')
});
// Sidebar icon — appears above Explore and above Search
context.ui.registerButton({
id: 'plugin-panel',
location: 'sidebar-actions',
label: 'Plugin Panel',
icon: '🧩',
onClick: () => context.log('Plugin panel clicked!')
});
},
onUnload: () => {
// All registered buttons are automatically cleaned up
}
};
Unregistering Buttons
Buttons are automatically unregistered when the plugin is unloaded. To manually unregister:
context.ui.unregisterButton('my-button-id');
TypeScript Types
import type { UIButtonDefinition, UIButtonPosition, UILocation } from '@paarrot/plugin-manager';
const button: UIButtonDefinition = {
id: 'my-button',
location: 'text-composer-toolbar',
label: 'My Action',
icon: '🎨',
position: {
group: 'my-tools',
after: 'emoji-picker',
order: 1
},
onClick: () => console.log('Clicked!')
};