The frontend of Odoo 19 uses the OWL (Odoo Web Library), which is a framework for developing JS components. The components are designed as modules that can be inherited and extended in order to create customizations without affecting any core files.
There are two methods for implementing widget inheritance:
- JS Component Inheritance
- HTML Template Inheritance
1. Inheritance of Widgets Using JavaScript
In JavaScript, inheritance is achieved through the use of the extends keyword to derive a child class from an OWL component.
/** @odoo-module **/
import { OriginalWidget } from "path/to/widget";
import { registry } from "@web/core/registry";
export class CustomWidget extends OriginalWidget {
setup() {
super.setup();
// add your custom logic here
}
}
Why super.setup() Matters
The setup() function is responsible for setting up state, services, hooks, and handlers. It's important to always call super.setup() first to ensure correct initialization.
Example: Extend CharField to Return Uppercase Values
/** @odoo-module **/
import { CharField } from "@web/views/fields/char/char_field";
import { registry } from "@web/core/registry";
export class UpperCaseField extends CharField {
setup() {
super.setup();
}
get formattedValue() {
const val = super.formattedValue;
return val ? val.toUpperCase() : val;
}
}
registry.category("fields").add("uppercase_char", {
component: UpperCaseField,
displayName: "Uppercase Char",
supportedTypes: ["char"],
});
Usage in view XML:
<field name="name" widget="uppercase_char"/>
Overriding Methods
Override any parent’s method and invoke super to retain existing functionality:
export class CustomWidget extends OriginalWidget {
onItemClicked(item) {
super.onItemClicked(item);
console.log("Item clicked:", item.id);
}
}This is useful for adding validations, logging user actions, showing notifications, or injecting business logic.
2. XML Template Inheritance
XML inheritance changes the component's rendered HTML. OWL templates use t-inherit and t-inherit-mode.
In extension mode, we will include a badge in the many2one container:
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="my_module.CustomMany2One"
t-inherit="web.Many2One"
t-inherit-mode="extension"
owl="1">
<xpath expr="//div[hasclass('o_many2one')]" position="inside">
<span class="badge bg-success ms-2">Verified</span>
</xpath>
</t>
</templates>
t-inherit-mode="extension" overrides the existing web.template.Many2One. The badge appears wherever Many2One template is applied.
Primary mode — new template created on the basis of Many2One template (for example, for VIP badge to be shown only for certain values):
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="my_module.VipMany2One"
t-inherit="web.Many2One"
t-inherit-mode="primary"
owl="1">
<xpath expr="//div[hasclass('o_field_many2one_selection')]" position="before">
<span t-if="props.value and props.value[1] and props.value[1].includes('VIP')"
class="badge bg-warning text-dark ms-2 fw-bold">
? VIP Client
</span>
</xpath>
</t>
</templates>
t-inherit-mode="primary" creates an entirely new template. The original Many2One field on the web does not get impacted by this.
For using this custom template, you need to write a custom JS widget and import this template into it:
/** @odoo-module **/
import { Many2OneField } from "@web/views/fields/many2one/many2one_field";
import { Many2One } from "@web/views/fields/many2one/many2one";
import { registry } from "@web/core/registry";
class VipMany2One extends Many2One {
static template = "my_module.VipMany2One";
}
class VipMany2OneField extends Many2OneField {
static components = { Many2One: VipMany2One };
}
registry.category("fields").add("vip_many2one", {
component: VipMany2OneField,
displayName: "VIP Many2One",
supportedTypes: ["many2one"],
});
Asset Registration
Each JS and XML file needs to be registered in __manifest__.py as below:
'assets': {
'web.assets_backend': [
'my_module/static/src/js/custom_widget.js',
'my_module/static/src/xml/custom_widget.xml',
],
},Widget inheritance is one of the most powerful frontend features in Odoo 19. It allows developers to customize existing OWL widgets cleanly without modifying core files.
To read more about Overview of Different Types of Inheritance in Odoo 19, refer to our blog Overview of Different Types of Inheritance in Odoo 19.