Skip to main content
iVentureTeam

popover_widget

An icon in a cell that opens a popover when clicked, with the message, the icon, the color and the position all decided server side and shipped as JSON in a text field.

Siddharth JambukiyaSiddharth JambukiyaOdoo Techno-Functional Consultant
August 27, 2026Updated September 8, 20266 min read
Technical namepopover_widget
Field typeschar
Viewslist, form, kanban
Modulestock, the Inventory app
Used in core1 occurrence directly, the package list in stock, plus several widgets that extend it
VersionsOdoo 20.0, Odoo 19.0, Odoo 18.0, Odoo 17.0, Odoo 16.0
No-code setupNo. The JSON payload has to be computed server side
Alternativesgrouped_view_widget, badge, stock_rescheduling_popover, actionable_errors

What the JSON popover field does

Some rows in an inventory list need an explanation: this package is blocked, this move is late, this quantity is reserved elsewhere. The explanation is short, it only applies to some rows, and giving it a column would waste space on every row that does not need one.

This widget is Odoo's answer. It renders a small icon in the cell, and clicking it opens a popover with the explanation. Everything about that, the text, which icon, what color and which side the popover appears on, comes from a JSON string the server puts in the field.

Because the configuration travels with the data rather than living in the view, one column can show a red warning on one row, a blue information note on another, and nothing at all on a third. A row whose field is empty simply renders the icon with its defaults.

What this means for your team

The value is contextual explanation without a column. On an inventory screen where a handful of rows have a problem, this is the difference between a list that flags its own exceptions and one that requires a report to interpret.

It is also a genuinely reusable building block for custom work. Any list where the server can decide that a particular row needs a note can use it: a credit hold on a customer, a certification expiring on an employee, a quality alert on a lot. The server writes the JSON, the view names the widget, and no client code is needed.

The one thing to plan for is the Odoo 20 icon change. Payloads that name Font Awesome icon classes today will need updating, and because the icon is data rather than view XML, the change is in your server code rather than in a view you can patch.

Supported options in Odoo 19

There are no XML options. Everything is configured through keys in the JSON value, and the source documents them in a comment block above the class. The table below is that documented set, verified against the code. Read from popover_widget.js, Odoo 19.0.

OptionTypeWhat it does
msgkey in the JSON valueThe popover's text. Required unless a custom template is supplied that renders something else.
iconkey in the JSON valueThe icon class shown in the cell. In Odoo 19 this is a Font Awesome class; on the development branch the convention changes to a Material Symbols name.(default: fa-info-circle)
colorkey in the JSON valueThe icon's color class, so a warning can be red and a note blue on the same column.(default: text-primary)
positionkey in the JSON valueWhich side the popover opens on. Read once when the component starts, so it cannot change per click.(default: top)
popoverTemplatekey in the JSON valueNames your own template for the popover body. Every other key in the JSON is passed into it as a prop, along with the record.(default: the built-in content template)

Unknown keys are not ignored. The whole parsed object is spread into the popover's props, so any extra key you put in the JSON is available inside a custom template. That is the documented way to pass data through, and it also means a typo in a documented key silently becomes an unused prop rather than an error.

Working examples

The core usage

<field name="json_popover" widget="popover_widget"
       nolabel="1" width="18px"
       invisible="not json_popover"/>

The narrow width and the visibility guard are part of the pattern: the column is a marker, not a data column.

A minimal payload

{
  "msg": "This package is blocked by a quality alert.",
  "color": "text-danger",
  "position": "right"
}

Written by the server into the char field. The icon falls back to the default information circle.

Your own popover template

{
  "popoverTemplate": "my_module.MyPopover",
  "lines": ["first", "second"],
  "icon": "fa-warning"
}

Any key beyond the documented ones, here the list of lines, arrives in the template as a prop.

Everything the JSON carries becomes a prop

The setup does four things and then stops. It parses the field value, falling back to an empty object if the field is empty or unset, reads the position out of it to configure the popover hook, and reads the color and icon with defaults. Everything else waits for a click.

Opening the popover passes the entire parsed object plus the record itself as props. That is what makes custom templates work: they receive whatever the server chose to include, and they can read the record too. It also explains why the widget declares its popover component's props as an explicit record entry plus a catch-all.

Parsing in setup rather than in a getter has the usual consequence. If the server recomputes the field while the row is on screen, the icon and popover keep the old payload until the component is recreated. On a list that reloads after each operation this is invisible; on a form that updates in place it is not.

The file is unusually explicit about being a base class. A comment at the top explains that to add behavior you extend both the popover component and the field, and set the new popover as the field's component. Several Odoo widgets do exactly that, which is why this one has more users than its single direct usage suggests.

The default icon is the one thing that moves in the next version. On the development branch both the documented default and the fallback in the code change from a Font Awesome class to a Material Symbols name, so a payload that passes an old style class will point at an icon that no longer exists.

Version compatibility

VersionStatusNotes
Odoo 20.0Partial / changedNot released. The default icon and the documented convention move from Font Awesome to Material Symbols.
Odoo 19.0VerifiedVerified against the shipped source. Unchanged in substance from Odoo 18.
Odoo 18.0VerifiedIdentical behavior and the same four documented keys.
Odoo 17.0VerifiedIdentical behavior.
Odoo 16.0VerifiedSame JSON contract and defaults.

Upgrade note. The JSON contract and the four documented keys have been stable since Odoo 16, so server-side code that writes these payloads carries over. Odoo 19 changed nothing but the module marker comment. The change that will need work is the icon naming in Odoo 20, described below.

What is changing in Odoo 20

Odoo 20 is expected at Odoo Experience in Brussels, 24 to 26 September 2026. The development branch is unstable and this may still change; we re-verify the page after release.

The icon convention changes. The default icon becomes a Material Symbols name instead of a Font Awesome class, and the documentation comment is updated to match. Everything else, including the message, color and position keys and the pass-through of extra props, is identical.

Plan for your payloads. Because the icon is written by your server code rather than in a view, any custom module producing these payloads with Font Awesome class names has to be updated as part of the upgrade. Nothing will error; the icon will simply not render.

Common problems and fixes

SymptomCause and fix
The icon shows but the popover is emptyThe payload has no message key and no custom template that renders something else. Include the message key, or supply a template that uses the keys you do send.
The icon appears on every rowThe field is not empty on rows that need no note, or the view has no visibility guard. Add an invisible expression on the field, as the core view does.
The icon does not update after a recomputeThe payload is parsed once when the component starts. Reload the list; the record's field is correct, only the rendered copy is stale.
A custom template gets no dataThe keys were misspelled, so they arrive as different props. Match the key names to what the template reads; every key becomes a prop.
The position key does nothingIt is read once at setup to configure the popover hook. Expected. The position cannot vary between clicks on the same rendered cell.
No icon renders in Odoo 20The payload passes a Font Awesome class and the convention has changed to Material Symbols. Update the server-side code that writes the payload.

JSON popover field vs the alternatives

WidgetBest forKey difference
popover_widgetPer-row explanations computed on the server and shown on demandAn icon and popover configured entirely by a JSON payload, with unknown keys passed through as props
grouped_view_widgetTabular previews from a JSON payloadRenders a table inline rather than an icon and popover
badgeA short state shown inlineAlways visible, no popover and no payload
stock_rescheduling_popoverRescheduling explanations in inventoryA widget built by extending this one, with its own behavior
actionable_errorsErrors that come with an action to takeOffers buttons rather than static explanatory text

If the explanation is the same for every row, a column tooltip or a static help text is simpler and needs no payload. This widget earns its place when the message is per record and computed. And if you need behavior beyond showing text, extend it as the source invites rather than writing a new widget: several core inventory widgets are built that way.

Frequently asked questions

How is the popover configured?+
Entirely from a JSON string in the field. Four keys are documented in the source: the message, the icon class, the color class and the position. A fifth names your own template.
Can I pass extra data to a custom template?+
Yes, and that is the documented approach. The whole parsed object is spread into the popover's props, so any key you add is available in the template alongside the record.
Why does the icon not change after the server recomputes the field?+
The payload is parsed once when the component starts. The record is updated correctly; the rendered copy is stale until the row is redrawn.
What happens if the field is empty?+
It parses as an empty object, so the icon renders with its defaults and the popover has no message. Core avoids that by hiding the field when it is empty.
What changes in Odoo 20?+
The icon convention. The default becomes a Material Symbols name rather than a Font Awesome class, so payloads written by custom code need updating or their icon will not render.

Inventory screens that explain their own exceptions

Blocked packages, late moves and reservation conflicts are easier to fix when the list says why. We build that kind of contextual guidance into Odoo Inventory on versions 16 through 19, server side and in the interface.

Book a free consultation

How this page was produced

The four documented keys, the defaults, the pass-through of extra props, the parse in setup and the extension comment were read from popover_widget.js on the Odoo 19.0 branch, with the usage taken from stock/views/stock_package_views.xml. Version coverage comes from comparing the file across the 16.0, 17.0 and 18.0 branches, and the icon change from the public development branch. Spotted an error? Tell us and we will correct the page.