With the continued evolution of Odoo’s JavaScript framework, OWL (Odoo Web Library) remains the backbone of Odoo’s modern front-end architecture. In Odoo 19, OWL provides even better component-based development, reactivity, and extensibility.
One powerful feature developers frequently rely on is mixins, a mechanism that allows you to share reusable logic across components.
In this blog, we will walk you through what an OWL mixin is, why it is useful, and how to create and use a custom mixin in Odoo 19.
What is an OWL mixin?
An OWL mixin is a simple JavaScript object that contains reusable functions or lifecycle behavior.
Adding the mixin to an OWL component allows you to extend its functionality without inheritance, keeping your code modular and clean.
Mixins are useful for:
- Logging
- Event handling
- Common UI behavior
- Shared utility functions
- Enhancing components dynamically
Step-by-Step Guide to Creating an OWL Mixin in Odoo 19
Step 1: Create the Module Structure
First, create your custom Odoo module with the following structure:
owl_mixin/
+-- __init__.py
+-- __manifest__.py
+-- static/
¦ +-- src/
¦ +-- js/
¦ +-- mixin.js
¦ +-- owl.js
¦ +-- service.js
Step 2: Define the Manifest File
Create your __manifest__.py:
{
'name': 'OWL Mixin Demo',
'version': '19.0.1.0.0',
'category': 'Technical',
'summary': 'Demonstrates OWL Mixin pattern in Odoo 19',
'depends': ['web'],
'assets': {
'web.assets_backend': [
'owl_mixin/static/src/js/mixin.js',
'owl_mixin/static/src/js/owl.js',
'owl_mixin/static/src/js/service.js',
],
},
'installable': True,
'application': False,
}Step 3: Create the Mixin
Now, let's create the actual mixin in mixin.js:
/** @odoo-module **/
/**
* LoggerMixin
* Adds reusable logging behavior to OWL components
*/
export function LoggerMixin(BaseComponent) {
return class extends BaseComponent {
setup() {
super.setup();
console.log("[LOGGER MIXIN] setup executed");
}
logInfo(message) {
console.log("[LOGGER MIXIN][INFO]", message);
}
logWarn(message) {
console.warn("[LOGGER MIXIN][WARN]", message);
}
logError(message) {
console.error("[LOGGER MIXIN][ERROR]", message);
}
};
}
Step 4: Create a Component Using the Mixin
In owl.js, create a component that uses the mixin:
/** @odoo-module **/
import { Component, onMounted, xml } from "@odoo/owl";
import { LoggerMixin } from "./mixin";
/**
* Base component
*/
class LoggerDemoBase extends Component {
static template = xml`<div class="logger-demo">Logger Demo Component</div>`;
setup() {
super.setup();
console.log("[LOGGER DEMO] Base setup");
}
}
/**
* Final component with mixin applied
*/
export class LoggerDemo extends LoggerMixin(LoggerDemoBase) {
setup() {
super.setup();
this.logInfo("LoggerDemo initialized");
onMounted(() => {
console.log('[Logger Demo Test]');
this.logWarn("Sample warning log");
this.logError("Sample error log");
});
}
}
Step 5: Register as a Service (For Testing)
In service.js, create a service to auto-start your component:
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { LoggerDemo } from "./owl";
import { mount } from "@odoo/owl";
/**
* Auto-start LoggerDemo for console demonstration
*/
registry.category("services").add("logger_mixin_demo", {
start(env) {
console.log("[LOGGER DEMO] Service starting...");
// Create a hidden container for the component
const container = document.createElement('div');
container.style.display = 'none';
document.body.appendChild(container);
// Mount the component
mount(LoggerDemo, container, { env });
console.log("[LOGGER DEMO] Service started and component mounted");
},
});
Understanding How It Works
The mixin pattern in OWL works through composition rather than traditional inheritance:
- LoggerMixin is a Higher-Order Function: It takes a base component class and returns a new class that extends it
- Method Injection: The mixin adds new methods (logInfo, logWarn, logError) to any component
- Lifecycle Hook Enhancement: The setup() method is augmented while preserving the base behavior via super.setup()
- Multiple Mixins: You can chain multiple mixins together like: MixinA(MixinB(MixinC(BaseComponent)))
Best Practices
- Keep mixins focused: Each mixin should have a single responsibility
- Always call super.setup(): Ensure the component lifecycle works correctly
- Document your mixins: Add clear JSDoc comments explaining what the mixin does
- Avoid state in mixins: Prefer utility functions over stateful logic
- Use descriptive names: Name mixins based on what they provide (e.g., LoggerMixin, ValidationMixin)
Conclusion
OWL mixins in Odoo 19 provide a clean, powerful way to share functionality across components. By using the composition pattern, you can build modular, maintainable code that's easy to test and extend. Whether you're adding logging, validation, or any other cross-cutting concern, mixins keep your components lean and focused on their primary responsibilities.
To read more about An Overview of OWL Components in Odoo 18, refer to our blog An Overview of OWL Components in Odoo 18.