Skip to main content
iVentureTeam

web_ribbon

The corner banner on Odoo forms, Archived, Paid, Cancelled, is one reusable view widget: web_ribbon. It takes three attributes, and one undocumented sizing rule.

Siddharth JambukiyaSiddharth JambukiyaVerified on Odoo 19.0 · Updated August 10, 2026

Quick summary

  • web_ribbon is a view widget, written as <widget name="web_ribbon"/> in form views; it is not a field and stores nothing.
  • It draws the diagonal banner in the form's top-right corner: Archived, Paid, Cancelled and friends.
  • Three attributes, verified in the source: title (the text), bg_color (a Bootstrap background class), tooltip (hover text).
  • Show and hide it with the standard invisible expression, exactly like a field.
  • Undocumented and verified: the ribbon auto-shrinks its font when the text passes 10 and again past 15 characters.
  • Default color is the green text-bg-success; danger red is the usual choice for Archived.
  • Used 157 times across core, and unchanged in the Odoo 20 development branch.
Technical nameweb_ribbon
Viewsform (view widget, element)
Moduleweb, present in every Odoo database
Used in core157 occurrences across dozens of modules, including account, crm, calendar, base_automation, analytic
VersionsOdoo 20.0, Odoo 19.0, Odoo 18.0, Odoo 17.0, Odoo 16.0
No-code setupNo. Ribbons are added in view XML (Studio has no ribbon element)
Alternativesbadge, statusbar, boolean_toggle

What the ribbon widget does

Some information about a record is state, not data: this contact is archived, this invoice is paid, this event is cancelled. Odoo's convention for shouting state without using a field slot is the diagonal corner ribbon, and every one of them is this widget.

Because it is a view widget rather than a field widget, it appears in XML as a <widget> element, not a <field>. It has no value, saves nothing, and exists purely to render. What it shows and when it shows are driven entirely by the attributes you give it and an invisible condition over the record's fields.

What this means for your team

The ribbon is the difference between a user noticing a record's state and missing it. An archived supplier that still looks active gets purchase orders; a paid invoice that does not visibly say so gets a second reminder call. The diagonal banner is deliberately unmissable, which is why core reserves it for states that change how you should treat the whole record.

Used well, ribbons also carry your process language. A Blocked ribbon on quality-hold products, a VIP ribbon on key accounts, a Do not invoice ribbon on internal projects: each is a one-line view change that spares a training slide and a support thread. The discipline is scarcity. One ribbon on a form is a signal; three are wallpaper, and the widget will happily render all three if told to, overlapping.

Supported options in Odoo 19

A view widget takes attributes on the element, not an options dictionary. All three verified in ribbon.js, Odoo 19.0 web module, plus the legacy alias read from extractProps.

OptionTypeWhat it does
titlestring (attribute)The text on the ribbon. Keep it within about 15 characters; the widget shrinks the font past 10 and again past 15.
bg_colorstring (attribute)Bootstrap background class for the banner: text-bg-danger, text-bg-warning, text-bg-info, and so on.(default: text-bg-success)
tooltipstring (attribute)Hover text on the ribbon, for the one-line explanation of the state.
textstring (attribute)Legacy alias for title, still read by extractProps when title is absent. Use title in new views.

Color values are Bootstrap background classes, passed as-is to the element: text-bg-danger, text-bg-warning, text-bg-info and the rest. The source's default is text-bg-success. Anything Bootstrap accepts as a background class works, which also means a custom class of your own is legal if your assets define it.

Working examples

The classic Archived ribbon

<widget name="web_ribbon" title="Archived"
        bg_color="text-bg-danger"
        invisible="active"/>

Visible only when active is False. Place it as the first element inside the <sheet> so it anchors to the corner.

State ribbon with a tooltip

<widget name="web_ribbon" title="Paid"
        tooltip="Fully paid on the payment date"
        invisible="payment_state != 'paid'"/>

Default green, hover text for the why. Any field used in the invisible expression must be present in the view, invisible fields count.

Two mutually exclusive ribbons

<widget name="web_ribbon" title="Cancelled" bg_color="text-bg-danger"
        invisible="state != 'cancel'"/>
<widget name="web_ribbon" title="Done"
        invisible="state != 'done'"/>

Both declared, conditions guaranteeing only one renders at a time. This is the core pattern for state ribbons.

The hidden auto-sizing rule

One rendering rule in the source is documented nowhere else: the ribbon resizes itself by text length. Up to 10 characters renders full size; past 10 characters the component adds its medium class; past 15 it adds the small one. That is why Archived looks bigger than a custom Pending validation ribbon, and why very long ribbon text looks cramped no matter the color.

The practical guidance follows directly: keep ribbon text within about 15 characters, and treat anything longer as a sign the message belongs in a banner or an activity, not a corner ribbon. Translations count too; a 9-character English title can become a 19-character German one and drop two sizes.

Also read from the source: the text attribute is a legacy alias that extractProps accepts when title is absent. You will meet it in older custom modules; write title in anything new.

Version compatibility

VersionStatusNotes
Odoo 20.0In developmentNot released. The development branch shows no changes to this widget; see below.
Odoo 19.0VerifiedVerified against the shipped source and tested on a clean database.
Odoo 18.0VerifiedSame attributes and behavior. No XML changes needed.
Odoo 17.0VerifiedSame attributes and behavior. No XML changes needed.
Odoo 16.0VerifiedSame attributes and behavior. No XML changes needed.

Upgrade note. Older databases sometimes carry ribbons written with the text attribute or pre-Bootstrap-5 color classes like bg-danger. Both still render, but standardize on title and text-bg-* classes during a migration cleanup so views match current core conventions.

What is changing in Odoo 20

Odoo 20 is expected at Odoo Experience in Brussels, 24 to 26 September 2026. We read the widget's file on the public development branch at the time of writing.

No changes: attributes, defaults, the auto-sizing thresholds and the registration are identical to Odoo 19. The only movement is internal, to the new Owl props syntax, which affects JavaScript patches and nothing in XML. We re-verify this page once Odoo 20 ships.

Common problems and fixes

SymptomCause and fix
Ribbon never appearsThe invisible expression references a field that is not loaded in the view. Add the field to the form, invisible="1" is enough, then re-test the condition.
Ribbon shows on every recordNo invisible condition, so the widget renders unconditionally. Add invisible="..." with the state expression that should gate it.
Text is tiny or crampedThe auto-sizing rule: past 10 characters the font shrinks, past 15 it shrinks again. Shorten the title; check translated lengths too.
Color did not changeA plain color name or pre-Bootstrap-5 class was passed. Use a text-bg-* class, e.g. bg_color="text-bg-warning".
Two ribbons overlapBoth invisible conditions are true at the same time; the widget does not arbitrate. Make the conditions mutually exclusive.
Ribbon sits in the wrong placeThe widget element is nested deep in the sheet instead of at its top. Declare it as the first element inside <sheet>.

Ribbon widget vs the alternatives

WidgetBest forKey difference
web_ribbonUnmissable record state on a form: Archived, Paid, CancelledPure view element, no field and no stored value; gated by an invisible expression
badgeState shown inline next to data, in lists and formsA field widget rendering the value as a colored pill, one per row
statusbarA workflow the user moves throughShows all stages and allows clicking between them, in the form header
boolean_toggleA state the user flips directlyAn editable switch bound to a boolean field, not a display banner

The practical test: if the message is about the record's state and should be impossible to miss, it is a ribbon. If it needs to be dismissed, explain itself at length, or appear on many records at once, it is an alert banner or an activity instead.

Frequently asked questions

How do I add an Archived ribbon to a custom model's form?+
Give the model the standard active boolean, then add <widget name="web_ribbon" title="Archived" bg_color="text-bg-danger" invisible="active"/> as the first element inside the form's sheet. Odoo's archive action toggles active, and the ribbon follows.
Can I show a ribbon based on any condition?+
Yes. The invisible attribute takes the same expressions as fields, over any fields present in the view. Amount thresholds, states, dates, anything the record exposes works.
What colors can a ribbon have?+
Any Bootstrap background class via bg_color: text-bg-danger, text-bg-warning, text-bg-info, text-bg-dark and the rest. The default when you set nothing is the green text-bg-success.
Why is my ribbon text so small?+
The widget resizes by text length, a rule visible only in the source: past 10 characters it steps down once, past 15 it steps down again. Shorten the title, and remember translations can push a short English title over the limit.
Is there a way to add ribbons from Odoo Studio?+
No. Studio's component palette has no ribbon element, so ribbons are added in view XML. It is a two-line change, and the kind of small view work we handle routinely in customization engagements.
Does web_ribbon work in list or kanban views?+
It is designed and positioned for form views. Kanban cards get state color through their own card styling or a badge field; lists use decorations or the badge widget.

Want your record states impossible to miss?

Ribbons, badges and status logic are small view changes with outsized usability payoff, and they need someone comfortable in Odoo's view XML. We deliver exactly this kind of form polish as part of Odoo customization work on 16 through 19.

Book a free consultation

How this page was produced

The attribute table, the defaults and the auto-sizing thresholds were read from the Odoo 19.0 web module source (ribbon.js) and confirmed on a clean Odoo 19 database, where the screenshot was captured. The Odoo 20 statement comes from reading the same file on the public development branch, where it is unchanged. Spotted an error? Tell us and we will correct the page.

Siddharth Jambukiya

Written by Siddharth Jambukiya

Get our monthly Odoo & automation digest

One short email per month with practical insights, version updates, and field-tested tips. No fluff, unsubscribe anytime.