Introduction
With the release of Odoo 19, the website frontend architecture has evolved significantly, making it more modular and dynamic through the Interaction API.
The new Interaction class provides a clean, declarative way to attach interactive JavaScript behaviors to website elements—similar to controllers but more component-driven.
In this guide, we’ll explore how to integrate an OWL component within an Interaction class to build a modern, reactive website feature in Odoo 19.
What Are Interactions in Odoo 19?
In Odoo 19, the Interaction system is a new mechanism that allows developers to attach frontend behaviors to elements using selectors.
It’s registered via the public.interactions registry and is automatically triggered when a matching DOM element appears.
This means you no longer need to rely solely on jQuery or custom publicWidget classes — you can use OWL-powered logic directly inside Interactions.
Use Case: A Hybrid Interaction + OWL Counter Component
Let’s build a simple example that combines:
- An Interaction class (using Odoo’s frontend registry)
- A small OWL component (with a reactive counter)
- A website snippet that mounts the component dynamically
This hybrid approach lets you take advantage of both:
- Declarative Interactions (for automatic lifecycle management)
- Reactive OWL Components (for dynamic UI updates)
Step 1: Create the OWL Component
Create a new file:
your_module_name/static/src/js/my_component.js
/** @odoo-module **/
import { Component, useState, xml } from "@odoo/owl";
import { registry } from "@web/core/registry";
export class MyOwlComponent extends Component {
setup() {
this.state = useState({
count: 0,
});
}
increment() {
this.state.count++;
if (this.props.onUpdate) {
this.props.onUpdate({
productId: this.props.productId,
count: this.state.count,
});
}
}
decrement() {
this.state.count--;
if (this.props.onUpdate) {
this.props.onUpdate({
productId: this.props.productId,
count: this.state.count,
});
}
}
}
MyOwlComponent.template = xml`
<div class="p-3 border rounded bg-light text-center">
<h6>OWL Counter for Product ID: <t t-esc="props.productId"/></h6>
<p class="my-2">Current Count: <strong><t t-esc="state.count"/></strong></p>
<div class="btn-group">
<button type="button" class="btn btn-sm btn-outline-primary" t-on-click="decrement">-</button>
<button type="button" class="btn btn-sm btn-outline-success" t-on-click="increment">+</button>
</div>
</div>
`;
MyOwlComponent.props = {
productId: { type: String },
onUpdate: { type: Function },
};
// Optional: register the component globally
registry.category("public_components").add(
"interaction_demo.MyOwlComponentTemplate",
MyOwlComponent
);
Here we’ve defined:
- A simple reactive counter
- A template written inline with xml
- A callback (onUpdate) that notifies the Interaction class when the component state changes
Step 2: Create the Hybrid Interaction
Create another JS file:
your_module_name/static/src/js/hybrid_interaction.js
/** @odoo-module **/
import { Interaction } from "@web/public/interaction";
import { mount } from "@odoo/owl";
import { registry } from "@web/core/registry";
import { MyOwlComponent } from "./my_component";
import { mount } from "@odoo/owl";
export class HybridInteraction extends Interaction {
static selector = ".hybrid-component";
async start() {
// Find the mounting target
const target = this.el.querySelector(".owl-mount-point");
// Mount the OWL component dynamically
this.owlComponent = await mount(MyOwlComponent, target, {
props: {
productId: this.el.dataset.productId,
onUpdate: this.onOwlUpdate.bind(this),
},
});
}
onOwlUpdate(data) {
console.log("OWL component updated:", data);
}
destroy() {
if (this.owlComponent) {
this.owlComponent.destroy();
}
super.destroy();
}
}
// Register the interaction
registry.category("public.interactions").add("hybrid_interaction", HybridInteraction);
This class:
- Automatically attaches to elements with .hybrid-component
- Mounts your OWL component inside .owl-mount-point
- Handles the OWL lifecycle (init + destroy)
- Logs component updates to the console
Step 3: Add HTML to a Website Page
In any website page (or snippet), add this markup:
<div class="hybrid-component" data-product-id="P1001">
<div class="owl-mount-point"></div>
</div>
When the page loads, Odoo’s frontend system will:
- Detect the .hybrid-component
- Trigger the HybridInteraction
- Mount your OWL component automatically
Step 4: Add to Manifest Assets
Make sure your assets are loaded in your module’s __manifest__.py:
'assets': {
'web.assets_frontend': [
'your_module_name/static/src/js/my_component.js',
'your_module_name/static/src/js/hybrid_interaction.js',
],
},Then upgrade your module and refresh the website page.
How This Works
Odoo 19’s frontend is built around Registries and Interactions:
- The Interaction class replaces the old publicWidget mechanism.
- It automatically detects matching elements via the selector.
- When the element appears, start() runs — perfect for initializing dynamic content.
By mounting an OWL component inside the interaction, you bridge:
- DOM-based initialization (Interaction)
- Reactive frontend logic (OWL)
This is extremely useful for:
- Product carousels
- Dynamic price calculators
- Interactive website widgets
- Snippets that require user interactions
Advantages of This Approach
- Modular: OWL logic and templates are encapsulated
- Automatic lifecycle management: destroy/unmount handled cleanly
- Reusable: can attach to multiple DOM elements dynamically
- Compatible: works seamlessly with Odoo’s new registry system
Conclusion
Using Odoo’s Interaction API with OWL components allows you to build powerful, reactive, and maintainable frontend behaviors for your Odoo 19 website.
This hybrid pattern represents the future of Odoo website development, replacing older jQuery-based widgets with a cleaner, more modern architecture.
Whether you’re building a small interactive snippet or a complex eCommerce UI, mastering this pattern will make your Odoo frontend development both efficient and scalable.
To read more about How to Use OWL Components on the Website Odoo 18, refer to our blog How to Use OWL Components on the Website Odoo 18.