Skip to main content
iVentureTeam

percentage

The percentage widget shows a stored fraction as percent: 0.15 displays as 15%, and typing 15 stores 0.15. One convention, consistently applied on both directions.

August 11, 2026Updated August 11, 20265 min read
Odoo 19 form showing a margin field rendered by the percentage widget as 15% while storing 0.15.
Studio namePercentage
Technical namepercentage
Field typesfloat, integer
Viewsform, list
Moduleweb, present in every Odoo database
Used in core38 occurrences across 21 modules, margins, rates and probabilities throughout
VersionsOdoo 20.0, Odoo 19.0, Odoo 18.0, Odoo 17.0, Odoo 16.0
No-code setupYes, via Odoo Studio (Enterprise)
Alternativesprogressbar, percentpie, float, monetary

What the Percentage widget does

Percentages have a storage convention problem: is 15% stored as 15 or as 0.15? Odoo core answers firmly, the fraction, and this widget is the translation layer that lets humans keep thinking in percent. The formatter multiplies by 100 and appends the symbol for display; the parser divides typed input back down; and while the field is being edited the symbol is dropped so users type against a clean number, all visible in the source's formatPercentage and parsePercentage wiring.

Decimals follow the digits setting, which, like a couple of other formatting widgets, the source accepts from either an option or an attribute, with its own comment admitting the duplication.

What this means for your team

The fraction convention is not pedantry; it is what keeps computed money right. A margin stored as 0.15 multiplies straight into amount * margin; stored as 15 it silently produces numbers a hundred times off the first time someone forgets the /100. Adopting this widget is really adopting the convention, and the payoff is that discounts, probabilities and rates all compose the same way across your models and reports.

The trap to brief your team on is imports and integrations: a spreadsheet column saying 15 loaded into a fraction field means 1500%. The widget can only translate at the UI; pipelines must respect the storage convention themselves.

Setting it up in Odoo Studio (no code)

Studio applies this widget without code.

  1. Open the view in Studio and select the float field.

  2. In Properties, set Widget to Percentage.

What Studio cannot do here

Decimal precision via digits is the XML step, and so is the judgment call the widget cannot make for you: whether the field's existing data already follows the fraction convention. Switching the widget on a field storing whole percents shows 1500% and needs a data migration first.

Supported options in Odoo 19

Verified against percentage_field.js in the Odoo 19.0 web module. One knob, reachable two ways, per the source's own comment.

OptionTypeWhat it does
digitsarray [width, decimals]Decimal precision of the displayed percent, e.g. [16, 1] for 12.5%. Accepted as an option or as a digits attribute; the attribute wins when both are set, per extractProps.

The attribute wins over the option when both are set: extractProps checks attrs.digits first and only falls back to options.digits. Same dual path, same precedence as the statinfo widget.

Working examples

A margin field

margin = fields.Float(string="Margin")  # stores 0.15 for 15%
<field name="margin" widget="percentage"/>

One decimal place

<field name="probability" widget="percentage"
       options="{'digits': [16, 1]}"/>

Displays 12.5%. The same value can be given as digits="[16, 1]" on the element; the attribute takes precedence when both exist.

Computed money staying honest

commission = fields.Monetary(compute="_compute_commission")

def _compute_commission(self):
    for rec in self:
        rec.commission = rec.amount_total * rec.margin  # fraction: no /100

One convention, three places

The whole widget is one convention applied in three places, and the places are worth naming because that is where bugs hide.

Display multiplies by 100 and appends %. Editing shows the percent number without the symbol, so what users type is what they mean. Parsing divides back to the fraction on save. UI round-trips are therefore lossless at the displayed precision.

Everything outside the UI bypasses all three: imports, XML-RPC writes, SQL, server actions. Whatever writes 15 into the field has written fifteen hundred percent, and the widget will faithfully display it as such. When a percentage looks absurd, the first question is which pipeline wrote the value raw.

Version compatibility

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

Upgrade note. Unchanged from Odoo 16 through 19; views carry over. Data conventions survive upgrades by definition, so any 15-versus-0.15 confusion predates the migration that revealed it.

What is changing in Odoo 20

Odoo 20 is expected at Odoo Experience in Brussels, 24 to 26 September 2026. The changes below are read from the public development branch and are not final until release.

Nothing changes for this widget. Same types, same digits handling, same formatter behavior. Internal syntax moves to the new Owl props system, affecting JavaScript patches only. We re-verify once Odoo 20 ships.

Common problems and fixes

SymptomCause and fix
Field shows 1500% instead of 15%The stored value is 15: something wrote whole percents into a fraction field, usually an import. Fix the pipeline to write 0.15, and migrate the existing data once.
User typed 0.15 and got 0.15%Typing means percent in this widget; 0.15 typed is 0.0015 stored. Type 15. One line in training covers it.
Too many or too few decimalsNo digits configured, or the option is being overridden by a digits attribute. Set digits explicitly; remember the attribute wins over the option.
% symbol vanishes while editingBy design: editing shows the clean number. Nothing to fix; the symbol returns on blur.
Computed results are 100x offModel code divides or multiplies by 100 around an already-fraction value. Audit the compute: with fractions stored, multiply directly.

Percentage widget vs the alternatives

WidgetBest forKey difference
percentageRates users read and type: margins, probabilities, discountsFraction stored, percent displayed and parsed, symbol hidden while editing
progressbarProgress toward 100% shown as a barVisual bar; reads the value, not focused on typing
percentpieA percentage stat in a smart buttonSmall pie gauge for the button box
floatPlain numbers without percent semanticsNo conversion, no symbol
monetaryAmounts of moneyCurrency-aware formatting instead of percent

The practical test: a rate users read and type, this widget. Progress toward completion, progressbar. A percentage inside a smart button, percentpie or statinfo. And a value that is genuinely a count out of a hundred rather than a ratio, store the number plainly with float and skip percent semantics.

Frequently asked questions

How does Odoo store percentage fields?+
Core convention, and this widget's contract: as the fraction. 15% is stored 0.15; the widget multiplies for display and divides what users type. Computed fields therefore use the value directly, with no /100.
Why does my percentage show as 1500%?+
Because 15 is stored where 0.15 belongs, almost always via an import or integration that wrote whole percents. The widget is displaying the stored value honestly; fix the data and the pipeline that wrote it.
How do I control decimals on a percentage field?+
With digits, e.g. options="{'digits': [16, 1]}" for one decimal. It also exists as an element attribute, and verified in the source, the attribute takes precedence when both are set.
What should users type into a percentage field?+
The percent they mean: typing 15 stores 0.15. While the field is focused the % symbol is hidden so the input stays a clean number.
Percentage or progressbar, which widget?+
Percentage is for reading and entering a rate. Progressbar visualizes advancement toward completion. Same underlying fraction convention, different jobs.
Does the widget work on integer fields?+
The source lists integer among supported types, but the fraction convention makes floats the practical choice; an integer can only hold 0% and multiples of 100%. Use float fields for real rates.

Margins and rates you can trust in every report?

Percent bugs are convention bugs: one import writing 15 instead of 0.15 poisons dashboards quietly. We set the conventions, fix the pipelines and build the computed fields on top, on Odoo 16 through 19.

Book a free consultation

How this page was produced

The formatter and parser wiring, the edit-time symbol behavior and the digits dual path with its precedence were read from the Odoo 19.0 web module source (percentage_field.js) and confirmed on a clean Odoo 19 database, where the screenshot was captured. The Odoo 20 statement comes from the same file on the public development branch, where it is unchanged. Spotted an error? Tell us and we will correct the page.