How to Add a Ribbon with Value in Odoo 18 POS Product Cards: Complete Guide
By Braincuber Team
Published on December 14, 2025
The Point of Sale (POS) application plays a key role in the Odoo ERP ecosystem, enabling businesses to efficiently handle and track daily sales activities. In this tutorial, we'll walk through a customization that enhances the POS interface by adding a ribbon to product cards, displaying important details directly on the product card.
Our goal is to overlay custom text onto product images inside the POS. To implement this, we will extend the existing ProductCard class and add logic to dynamically display the ribbon and text on the product image.
What You'll Learn:
- How to extend the ProductCard component in Odoo 18 POS
- Creating custom XML templates with OWL framework
- Adding CSS styling for ribbon elements
- Registering assets in the module manifest
Why Add Ribbons to POS Product Cards?
In Odoo 18, the Point of Sale module does not include a built-in ribbon or badge feature for product cards. However, ribbons can be incredibly useful for:
- Highlighting promotions - Display "Sale", "New", or "Hot" labels
- Stock indicators - Show "Low Stock" or "Last Items" warnings
- Product categories - Visually distinguish product types
- Custom messages - Any text relevant to your business
Because this functionality isn't available by default, we need to create a custom implementation. Let's get started!
Step 1: Create the Custom Module
First, create a new custom module with the standard Odoo module structure. You'll need the following files:
your_module/
├── __init__.py
├── __manifest__.py
├── static/
│ └── src/
│ ├── xml/
│ │ └── product_card.xml
│ └── css/
│ └── product_card.css
Step 2: Create the XML Template
The first step involves inheriting the ProductCard component so we can insert custom text inside the product box. Create a file named product_card.xml in your module's static/src/xml/ directory:
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-inherit="point_of_sale.ProductCard"
t-inherit-mode="extension"
owl="1">
<xpath expr="//div[contains(@class, 'product-img')]" position="inside">
<div class="pos-ribbon">
Hey Odoo
</div>
</xpath>
</t>
</templates>
Let's break down what this template does:
| Attribute | Purpose |
|---|---|
t-inherit |
Specifies the template to inherit from |
t-inherit-mode="extension" |
Extends the original template rather than replacing it |
owl="1" |
Enables the OWL framework for this template |
xpath |
Targets the product image div to insert our ribbon |
Step 3: Add CSS Styling
Create a CSS file named product_card.css in your module's static/src/css/ directory to style the ribbon:
.pos-ribbon {
position: absolute;
top: 6px;
left: 6px;
background: #ff4444;
color: white;
font-size: 12px;
padding: 3px 8px;
border-radius: 4px;
z-index: 20;
font-weight: bold;
}
You can customize the ribbon appearance by modifying these CSS properties:
- background - Change the ribbon color (e.g.,
#28a745for green) - top/left - Adjust the ribbon position
- font-size - Make the text larger or smaller
- border-radius - Change the corner roundness
- padding - Adjust the internal spacing
Step 4: Register Assets in Manifest
After creating the template and CSS files, you must register them in the module manifest by adding the files to the POS assets section:
# __manifest__.py
{
'name': 'POS Product Ribbon',
'version': '18.0.1.0.0',
'category': 'Point of Sale',
'summary': 'Add custom ribbons to POS product cards',
'depends': ['point_of_sale'],
'assets': {
'point_of_sale._assets_pos': [
'your_module_name/static/src/xml/product_card.xml',
'your_module_name/static/src/css/product_card.css',
],
},
'installable': True,
'auto_install': False,
}
Important: Replace your_module_name with the actual technical name of your module.
Step 5: Install and Test
After implementing the steps above:
- Restart Odoo to load the new module
- Update the Apps list in Odoo
- Install your custom module
- Open a POS session to see the ribbons on product cards
Advanced: Dynamic Ribbon Values
To display dynamic values (like product-specific text), you can extend the ProductCard JavaScript component:
/** @odoo-module */
import { ProductCard } from "@point_of_sale/app/generic_components/product_card/product_card";
import { patch } from "@web/core/utils/patch";
patch(ProductCard.prototype, {
get ribbonText() {
// Return dynamic text based on product properties
if (this.props.product.qty_available < 5) {
return "Low Stock";
}
return this.props.product.ribbon_text || "";
}
});
Then update your XML template to use the dynamic value:
<xpath expr="//div[contains(@class, 'product-img')]" position="inside">
<div t-if="ribbonText" class="pos-ribbon">
<t t-esc="ribbonText"/>
</div>
</xpath>
Conclusion
After implementing the steps above and adding the required code to your custom module, you'll be able to introduce a ribbon feature into the Odoo 18 POS interface. This enhancement provides a convenient way to display extra product information directly on the product card, improving clarity and usability for POS users.
The same technique can be extended to display dynamic values based on product properties, stock levels, or any custom field you add to your products.
Need Custom Odoo POS Development?
Our Odoo experts can help you customize your Point of Sale interface, add custom features, and optimize your retail operations.
