Powerbox Editors in Odoo 18
By Braincuber Team
Published on January 13, 2026
You're building a knowledge base module for your company. Users write articles, and they want to quickly insert templates, embed documents, or add special formatting without hunting through menus. They've seen how Notion and Slack let you type a forward slash and instantly access commands. You need the same experience in your Odoo editor—type / and a smart menu appears with all available actions.
Odoo 18 introduces Powerbox Editors, a modern interface pattern that transforms standard text fields into intelligent, command-driven editors. When users type / (slash) while editing, a contextual menu appears listing available commands grouped by category. Users can insert templates, embed components, add formatting, or trigger custom actions—all without leaving the keyboard. This tutorial shows you how to create custom Powerbox plugins that extend the editor with your own commands.
What is a Powerbox? A smart interface component in rich text editors. Type / to open a contextual command menu. Insert elements, trigger actions, or embed components—all from the typing area. Similar to Notion, Slack, and Discord command patterns.
Why Use Powerbox Editors?
Keyboard-First Workflow
Users never leave the keyboard. Type / followed by a command name to instantly access functionality. No mouse navigation through toolbars or menus.
Extensible Commands
Add custom commands specific to your module. Insert document templates, embed dynamic widgets, or trigger module-specific actions from the editor.
Organized Categories
Commands are grouped by category (formatting, media, knowledge). Users can browse or filter to find the right action quickly.
Undo/Redo Support
Powerbox actions integrate with the editor's history system. Every insertion or modification can be undone and redone seamlessly.
How Powerbox Works
POWERBOX ACTIVATION FLOW
═══════════════════════════════════════════════════════════
USER ACTION SYSTEM RESPONSE
───────────────────────────────────────────────────────────
1. User types "/" in editor → Powerbox menu opens
→ Shows all available commands
→ Grouped by category
2. User continues typing → Commands filter in real-time
(e.g., "/doc") → Only matching commands shown
3. User selects command → Command's run() method executes
(click or Enter) → Content inserted into editor
→ Action logged for undo/redo
4. User presses Escape → Powerbox menu closes
→ "/" character remains or removed
BUILT-IN COMMAND CATEGORIES
───────────────────────────────────────────────────────────
Category | Example Commands
───────────────────────────────────────────────────────────
Formatting | /heading, /quote, /code
Media | /image, /video, /file
Structure | /table, /columns, /divider
Knowledge | /article, /template, /embed
Custom | Your own plugin commands
COMMAND STRUCTURE
───────────────────────────────────────────────────────────
Each command defines:
• id - Unique identifier for the command
• title - Display name in the menu
• description - Brief explanation of what it does
• icon - FontAwesome icon class (fa-*)
• run() - Function executed when command selected
• categoryId - Which category to group under
Understanding the Plugin Architecture
Odoo's editor automatically creates a single Powerbox instance and stores it in its powerbox variable. You should never create another Powerbox manually. Instead, create plugins that register commands and configure options when the editor initializes.
Important: Supply your custom options when you initialize the editor, before it starts up. The Powerbox is created once—modifying it after initialization won't work as expected.
Creating a Custom Powerbox Plugin
Let's create a plugin that adds a "Document" command to the Knowledge editor. When users type /document, the plugin injects a predefined template into the article.
Create the Plugin File
Create a JavaScript file in your module's static folder:
your_module/static/src/js/article_document_plugin.js
/** @odoo-module **/
import { Plugin } from "@html_editor/plugin";
import { _t } from "@web/core/l10n/translation";
import { renderToElement } from "@web/core/utils/render";
import { KNOWLEDGE_PLUGINS } from "@knowledge/editor/plugin_sets";
export class ArticleDocumentPlugin extends Plugin {
// Unique identifier for this plugin
static id = "articleDocument";
// Dependencies this plugin needs
static dependencies = ["history", "dom"];
// Resources this plugin provides
resources = {
// Define the command
user_commands: [
{
id: "insertArticleDocument",
title: _t("Document"),
description: _t("Insert a document template"),
icon: "fa-file-text-o",
run: this.insertArticleDocument.bind(this),
},
],
// Register command in Powerbox
powerbox_items: [
{
categoryId: "knowledge",
commandId: "insertArticleDocument",
}
],
};
/**
* Insert the document template into the editor
*/
insertArticleDocument() {
// Render the template to a DOM element
const articleDocumentBlueprint = renderToElement(
"your_module.ArticleDocumentBlueprint"
);
// Insert the element at cursor position
this.dependencies.dom.insert(articleDocumentBlueprint);
// Log the change for undo/redo support
this.dependencies.history.addStep();
}
}
// Register the plugin in the Knowledge editor
KNOWLEDGE_PLUGINS.push(ArticleDocumentPlugin);
Create the XML Template
Create an XML template for the content that gets inserted:
your_module/static/src/xml/article_document_template.xml
<?xml version="1.0" encoding="UTF-8"?>
<templates>
<t t-name="your_module.ArticleDocumentBlueprint">
<div class="document-container"
data-embedded="DocumentContent"
contenteditable="true">
<!-- Document Header -->
<div class="document-header">
<h3>Document Title</h3>
<p class="document-meta">
Created: <span class="date"></span>
</p>
</div>
<!-- Document Body -->
<div class="document-body">
<p>Start writing your document content here...</p>
</div>
<!-- Document Footer -->
<div class="document-footer">
<p class="document-signature">Author: </p>
</div>
</div>
</t>
</templates>
Register Assets in Manifest
Add your files to the module's manifest:
{
'name': 'Custom Knowledge Documents',
'version': '18.0.1.0.0',
'depends': ['knowledge'],
'assets': {
'web.assets_backend': [
'your_module/static/src/js/article_document_plugin.js',
'your_module/static/src/xml/article_document_template.xml',
],
},
}
Complete Plugin Example: Meeting Notes
Here's a more comprehensive example—a plugin that inserts a structured meeting notes template with sections for attendees, agenda, discussion, and action items.
/** @odoo-module **/
import { Plugin } from "@html_editor/plugin";
import { _t } from "@web/core/l10n/translation";
import { renderToElement } from "@web/core/utils/render";
import { KNOWLEDGE_PLUGINS } from "@knowledge/editor/plugin_sets";
export class MeetingNotesPlugin extends Plugin {
static id = "meetingNotes";
static dependencies = ["history", "dom"];
resources = {
user_commands: [
{
id: "insertMeetingNotes",
title: _t("Meeting Notes"),
description: _t("Insert a meeting notes template"),
icon: "fa-users",
run: this.insertMeetingNotes.bind(this),
},
{
id: "insertActionItem",
title: _t("Action Item"),
description: _t("Add a task with assignee and due date"),
icon: "fa-check-square-o",
run: this.insertActionItem.bind(this),
},
],
powerbox_items: [
{
categoryId: "knowledge",
commandId: "insertMeetingNotes",
},
{
categoryId: "knowledge",
commandId: "insertActionItem",
}
],
};
insertMeetingNotes() {
const template = renderToElement(
"custom_knowledge.MeetingNotesTemplate"
);
this.dependencies.dom.insert(template);
this.dependencies.history.addStep();
}
insertActionItem() {
const template = renderToElement(
"custom_knowledge.ActionItemTemplate"
);
this.dependencies.dom.insert(template);
this.dependencies.history.addStep();
}
}
KNOWLEDGE_PLUGINS.push(MeetingNotesPlugin);
<?xml version="1.0" encoding="UTF-8"?>
<templates>
<!-- Meeting Notes Template -->
<t t-name="custom_knowledge.MeetingNotesTemplate">
<div class="meeting-notes" data-embedded="MeetingNotes">
<h2 class="meeting-title">Meeting: [Title]</h2>
<p class="meeting-meta">
<strong>Date:</strong> [Date] |
<strong>Time:</strong> [Time] |
<strong>Location:</strong> [Location/Link]
</p>
<h3>Attendees</h3>
<ul class="attendees-list" contenteditable="true">
<li>[Name] - [Role]</li>
</ul>
<h3>Agenda</h3>
<ol class="agenda-list" contenteditable="true">
<li>[Topic 1]</li>
<li>[Topic 2]</li>
</ol>
<h3>Discussion Notes</h3>
<div class="discussion-notes" contenteditable="true">
<p>[Meeting discussion and key points...]</p>
</div>
<h3>Action Items</h3>
<table class="action-items-table">
<thead>
<tr>
<th>Task</th>
<th>Assignee</th>
<th>Due Date</th>
<th>Status</th>
</tr>
</thead>
<tbody contenteditable="true">
<tr>
<td>[Task description]</td>
<td>[Name]</td>
<td>[Date]</td>
<td>Pending</td>
</tr>
</tbody>
</table>
</div>
</t>
<!-- Single Action Item Template -->
<t t-name="custom_knowledge.ActionItemTemplate">
<div class="action-item" data-embedded="ActionItem">
<input type="checkbox" class="action-checkbox"/>
<span class="action-text" contenteditable="true">
[Task description]
</span>
<span class="action-assignee">@[assignee]</span>
<span class="action-due">Due: [date]</span>
</div>
</t>
</templates>
Plugin Development Best Practices
✅ Follow These Guidelines:
- Always call addStep(): After inserting content, call
this.dependencies.history.addStep()to enable undo/redo - Use translations: Wrap user-facing strings with
_t()for internationalization - Choose clear icons: Use FontAwesome icons that represent the command's action (fa-file, fa-users, etc.)
- Write helpful descriptions: The description appears in the Powerbox—make it explain what the command does
- Use unique IDs: Both plugin ID and command IDs must be unique across all plugins
- Set contenteditable: Mark editable sections in templates with
contenteditable="true" - Use data-embedded: Mark your container with
data-embeddedto identify it as an embedded component - Register in the right plugin set: Use KNOWLEDGE_PLUGINS for Knowledge module, or create your own set
Common Issues and Solutions
Command Not Appearing in Powerbox
Verify that: (1) Your plugin is registered in the correct plugin set, (2) The categoryId in powerbox_items matches an existing category, (3) Your JS file is included in web.assets_backend.
Template Not Rendering
Check that: (1) The template name in renderToElement matches exactly with t-name in XML, (2) The XML file is included in assets, (3) The XML is valid (check browser console for errors).
Undo/Redo Not Working
Ensure you're calling this.dependencies.history.addStep() after every DOM modification. Missing this call breaks the editor's history tracking.
Conclusion
Powerbox Editors in Odoo 18 transform standard text fields into intelligent, command-driven interfaces. By creating custom plugins, you can add module-specific commands that insert templates, embed dynamic widgets, or trigger actions—all accessible by typing a simple slash. The plugin architecture is straightforward: define your command with an ID, title, description, and run function, then register it in the appropriate plugin set. Users experience a modern, keyboard-first workflow similar to Notion or Slack, making your Odoo editor a powerful, context-aware tool.
🎯 Key Takeaway: Create a Plugin class → Define user_commands with id, title, icon, and run() → Add to powerbox_items with categoryId → Create an XML template → Register in KNOWLEDGE_PLUGINS. Type / and your command appears.
