Introduction
In the world of programming, code reusability is extremely important—not only for the current developer but also for anyone who works on the project in the future. A clean and reusable code structure saves time, reduces errors, and makes development much easier. This is exactly where mixins become useful. A mixin is simply a reusable piece of code—such as a function or variable—that you can easily add to any OWL (Odoo Web Library) component.
The Anatomy of Mixins in Owl.js
Mixin in Owl.js is simply a function that takes a component and returns a new component with extra features. It acts like an add-on layer that you can attach to any component without rewriting the same logic again.
A mixin usually contains three main parts:
1. The Mixin Function
A mixin always starts as a normal JavaScript function:
export function TimerMixin(BaseComponent) {
//Body of function
}
TimerMixin = name of the mixin
BaseComponent = the component you want to extend
This makes the mixin flexible—you can apply it to any component.
2. Returning an Extended Class
Inside the mixin, we return a new class that extends the given component:
return class extends BaseComponent {
// extra features here
}This means:
- The original component keeps all its logic.
- The mixin adds extra behavior on top of it.
- The final component becomes a “combined” version.
3. Adding Reusable Logic
The returned class contains reusable logic like methods, states, or services:
setup() {
super.setup();
this.startTime = Date.now();
}
getElapsedTime() {
return Date.now() - this.startTime;
}Anything written inside becomes available to every component that uses this mixin.
Let's go through an example
A Reusable TimerMixin
/** @odoo-module **/
export function TimerMixin(BaseComponent) {
return class extends BaseComponent {
setup() {
super.setup();
this.startTime = null;
this.endTime = null;
}
startTimer() {
this.startTime = Date.now();
console.log("Timer Started");
}
stopTimer() {
this.endTime = Date.now();
const diff = this.endTime - this.startTime;
console.log("Timer Stopped:", diff, "ms");
return diff;
}
};
}
1. What the mixin does
This TimerMixin gives any OWL component the ability to:
- start a timer
- stop a timer
- calculate how long something took
How this works
export function TimerMixin(BaseComponent) {A mixin is a function that receives an existing component.
return class extends BaseComponent {This creates a new component with extra features added.
Inside setup()
setup() {
super.setup(); // keep original setup()
this.startTime = null; // new field
this.endTime = null; // new field
}This adds new variables to the component.
The reusable functions
Applying the Mixin
In this component, the mixin is applied by wrapping the base component with TimerMixin, which means the component automatically receives all the extra methods defined in the mixin—such as startTimer() and stopTimer(). When the component loads, it simply calls these methods as if they were its own, because the mixin has already added them behind the scenes. This allows the component to use the timer functionality without writing the same code again, making it clean, reusable, and easy to maintain.
/** @odoo-module **/
import { Component, onMounted } from "@odoo/owl";
import { TimerMixin } from "./timer_mixin";
class BaseDemoComponent extends Component {
static template = "DemoTimerComponent";
}
// Apply the mixin to the component
export class DemoComponent extends TimerMixin(BaseDemoComponent) {
setup() {
super.setup();
// Start timer on mount
onMounted(() => {
this.startTimer();
setTimeout(() => {
const time = this.stopTimer();
console.log("Time taken:", time, "ms");
}, 1500);
});
}
}
Here you can see that the component successfully uses the mixin’s methods to start and stop the timer, and the final execution time is printed in the console—showing how the mixin’s logic works in real action.

Demo template
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="DemoTimerComponent">
<div class="alert alert-info mt-3">
Timer Mixin Demo Loaded — check console logs!
</div>
</t>
</templates>
To make our demo component available inside Odoo’s web environment, we register it in the main_components registry. This tells Odoo that our component should be loaded automatically when the interface starts. By adding the component to the registry, Odoo recognizes it as an active UI element and mounts it without requiring any manual calls.
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { DemoComponent } from "./demo_component";
registry.category("main_components").add("demo_timer_component", {
Component: DemoComponent,
});
Note: Make sure all the required JavaScript and XML files (mixin file, demo component file, templates, etc.) are properly added to your module’s manifest so they load correctly in Odoo.
{
'name': "Pos Purchase Limit",
'version': '1.0',
'depends': ['base', 'point_of_sale'],
'application': True,
'auto_install': False,
'installable': True,
'website': 'www.cybrosys.com',
'data': [
'views/pos_purchase_limit_views.xml',
'views/pos_settings_purchase_limit.xml',
],
'assets': {
'point_of_sale._assets_pos': [
'odoo_mixin_example/static/src/js/timer_mixin.js',
'odoo_mixin_example/static/src/js/demo_component.js',
'odoo_mixin_example/static/src/js/demo_mount.js',
'odoo_mixin_example/static/src/xml/demo_template.xml',
]
},
}(This demonstration is implemented using the Odoo POS module.)
Conclusion
This is a small example, and you can apply the same mixin to any OWL component in Odoo. Mixins help you keep your code clean, reusable, and modular. Instead of rewriting the same logic again and again, you simply attach the mixin, and the component instantly gains new functionality. It’s an efficient and scalable way to structure your Odoo frontend code.
To read more about How to Create Owl mixin in Odoo 19, refer to our blog How to Create Owl mixin in Odoo 19.