How to Create a Custom Screen in POS in Odoo 18: Complete Step by Step Guide
By Braincuber Team
Published on March 31, 2026
In Odoo 18 Point of Sale (POS) system, extending functionality by adding custom screens is a common requirement for businesses with unique workflows. Custom screens allow you to display specialized information, collect additional data, or integrate with other systems. This complete tutorial will walk you through the process of creating a custom screen in Odoo 18 POS, complete with a custom button to trigger it. We'll cover the necessary XML templates, JavaScript components, and manifest configuration to implement this feature seamlessly.
What You'll Learn:
- How to structure a custom POS module with proper directory organization
- Creating XML templates for custom POS screens
- Building JavaScript components using OWL framework
- Adding custom buttons to the POS control bar
- Patching existing POS components to extend functionality
- Configuring the module manifest for proper asset loading
Step 1: Setting Up the Module Structure
Before diving into the implementation, let's examine the directory structure of our custom POS module. A well-organized structure is crucial for maintaining clarity and ensuring all components are properly loaded by Odoo.
custom_pos/
+-- static/
¦ +-- src/
¦ +-- js/
¦ ¦ +-- custom_button.js
¦ ¦ +-- custom_screen.js
¦ +-- xml/
¦ +-- custom_button.xml
¦ +-- custom_screen.xml
+-- __init__.py
+-- __manifest__.py
This structure separates JavaScript logic and XML templates into their respective directories under static/src/. The __init__.py and __manifest__.py files at the root level define the module's Python configuration and metadata.
Module Naming Convention
Use a unique module name like custom_pos to avoid conflicts with existing Odoo modules. Prefix with your company or project identifier for better organization in larger implementations.
Step 2: Creating the Custom Screen Template
The first step is to define the visual layout of your custom screen using an XML template. This template creates a full-screen container with your custom content.
This template creates a full-screen container with a simple heading. The t-name attribute defines the template's identifier, which we'll reference in our JavaScript component. The structure follows Odoo's POS styling conventions with classes like screen, h-100, and bg-100 for consistent appearance.
| CSS Class | Purpose | Effect |
|---|---|---|
| screen | POS screen container | Applies standard POS screen styling |
| h-100 | Full height | Sets height to 100% of parent container |
| bg-100 | Background color | Applies POS default background color |
| screen-full-width | Full width content | Content spans full screen width |
| d-flex | Flexbox layout | Enables flexbox for content alignment |
Step 3: Creating the JavaScript Component
Next, we need a JavaScript component to handle the screen's logic. This component uses Odoo's OWL framework and integrates with the POS system through the registry and hooks.
import { Component } from "@odoo/owl";
import { _t } from "@web/core/l10n/translation";
import { registry } from "@web/core/registry";
import { usePos } from "@point_of_sale/app/store/pos_hook";
export class CustomScreen extends Component {
static template = "custom_pos.CustomScreen";
setup() {
super.setup();
this.pos = usePos();
}
closeCustomScreen() {
this.pos.closeScreen();
}
}
registry.category("pos_screens").add("CustomScreen", CustomScreen);
This component extends Odoo's base Component class, specifies our XML template as its visual representation, and accesses the POS store via the usePos() hook. It also includes a method to close the screen and registers itself in the POS screens registry.
OWL Component
Extends Odoo's base Component class with the static template property pointing to our XML template.
POS Hook
The usePos() hook provides access to the POS store for screen navigation and state management.
Screen Registry
Registers the component in the pos_screens registry so POS can find and render it by name.
Close Method
The closeCustomScreen() method calls pos.closeScreen() to return to the previous POS screen.
Step 4: Adding a Custom Button to Trigger the Screen
To make our screen accessible, we'll add a button to the POS interface. This requires both an XML template for the button and JavaScript to patch the existing ControlButtons component.
Button XML Template
This template inherits from the existing point_of_sale.ControlButtons template and adds our custom button after the OrderlineNoteButton. The t-inherit-mode="extension" ensures we're extending rather than replacing the original template.
Button JavaScript
import { _t } from "@web/core/l10n/translation";
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
import { patch } from "@web/core/utils/patch";
import { ControlButtons } from "@point_of_sale/app/screens/product_screen/control_buttons/control_buttons";
patch(ControlButtons.prototype, {
onClick() {
// Open our custom screen
this.pos.showScreen("CustomScreen");
},
});
This code patches the existing ControlButtons component to add our onClick() method. When the button is clicked, it calls this.pos.showScreen("CustomScreen") to navigate to our custom screen. The patch mechanism ensures we're extending the original component without modifying Odoo's core code.
Understanding the Patch Mechanism
The patch() function from @web/core/utils/patch allows you to safely extend existing Odoo components. It merges your methods with the original prototype, ensuring compatibility with future Odoo updates. Always use patch instead of directly modifying prototypes.
Step 5: Configuring the Module Manifest
Finally, we tie everything together in the __manifest__.py file. This file declares the module's metadata, dependencies, and asset files that need to be loaded in the POS interface.
{
'name': 'Custom POS Features',
'version': '18.0.1.0.0',
'category': 'Point of Sale',
'sequence': 6,
'summary': 'Adds custom button and screen to POS',
'description': """
This module adds a custom button to POS that opens a custom screen.
""",
'depends': ['point_of_sale'],
'data': [],
'assets': {
'point_of_sale._assets_pos': [
'custom_pos/static/src/js/custom_button.js',
'custom_pos/static/src/js/custom_screen.js',
'custom_pos/static/src/xml/custom_button.xml',
'custom_pos/static/src/xml/custom_screen.xml',
],
},
'installable': True,
'auto_install': False,
}
The manifest declares dependencies on the POS module, bundles all our assets in the POS interface, and ensures our files are available in the correct loading order. The point_of_sale._assets_pos bundle is specifically designed for POS frontend assets.
| Manifest Key | Purpose | Value |
|---|---|---|
| depends | Module dependencies | ['point_of_sale'] |
| assets | Frontend asset files | JS and XML files in POS bundle |
| data | Backend data files | [] (empty — no XML records needed) |
| installable | Module availability | True — module can be installed |
| auto_install | Automatic installation | False — manual installation required |
Asset Loading Order Matters
List JavaScript files before XML templates in the assets array. The button JS should load before the screen JS if the button triggers the screen. Odoo processes assets in the order they appear in the manifest.
Step 6: Testing the Custom Screen
After implementing the custom POS screen module, install it and open your Odoo 18 Point of Sale interface. You should see the custom control button in the POS header bar.
Install the Module
Go to Apps, search for "Custom POS Features", and click Install. Ensure all dependencies are satisfied.
Open POS Session
Open a POS session and verify the "Custom Control Button" appears in the control bar with a link icon.
Click the Custom Button
Click the custom control button and verify that the custom screen appears with the heading "This is our custom screen".
Verify Screen Navigation
Test closing the screen and returning to the product screen. Verify that the POS state is preserved correctly.
Troubleshooting Tips
If the button doesn't appear, check the browser console for JavaScript errors. Verify that all assets are correctly listed in the manifest and that the module is properly installed. Clear the browser cache and restart the POS session after making changes.
Expanding Your Custom Screen
This tutorial provides the foundation for creating custom screens in Odoo 18 POS. From here, you can add forms, buttons, and business logic to make your custom screen truly useful for your specific use case. The Odoo POS framework offers many more capabilities that you can leverage once you've mastered these basic building blocks.
Custom Data Collection
Add input fields, dropdowns, and checkboxes to collect additional customer or order information during the POS transaction.
Backend Integration
Connect your custom screen to backend models using RPC calls to fetch and store data in Odoo's database.
Complex User Interactions
Implement multi-step workflows, validation rules, and dynamic content based on the current order state.
Third-Party Integration
Integrate with external systems like payment gateways, loyalty programs, or inventory management tools.
Frequently Asked Questions
How do I add a custom screen to Odoo 18 POS?
Create an XML template for the screen layout, a JavaScript component using OWL that registers in the pos_screens registry, and a custom button that calls pos.showScreen() to navigate to your screen.
What is the patch function in Odoo?
The patch function from @web/core/utils/patch safely extends existing Odoo components by merging your methods with the original prototype. It ensures compatibility with future Odoo updates without modifying core code.
How do I close a custom POS screen?
Call this.pos.closeScreen() from within your component. This method is provided by the POS store through the usePos() hook and returns the user to the previous screen in the POS flow.
Where should I place POS assets in the manifest?
Place POS frontend assets under the 'point_of_sale._assets_pos' key in the assets dictionary. List JavaScript files before XML templates, and ensure the loading order matches your component dependencies.
Can I add forms and data collection to a custom POS screen?
Yes, you can add input fields, dropdowns, and buttons to your custom screen XML template. Use OWL's reactive state management to handle form data and RPC calls to communicate with backend models for data persistence.
Need Help with Odoo POS Customization?
Our experts can help you build custom POS screens, integrate with third-party systems, and optimize your Point of Sale workflows for maximum efficiency and user experience.
