Skip to main content
iVentureTeam

project_task_progressbar

The bar that shifts from green to orange to red as a task eats its allocated hours is project_task_progressbar: a fork of the standard progress bar that multiplies by 100 and colors itself by fixed thresholds.

Siddharth JambukiyaSiddharth JambukiyaOdoo Techno-Functional Consultant
August 19, 2026Updated August 19, 20266 min read
Odoo 19 task list showing project_task_progressbar bars in green, orange and red according to hours spent versus allocated.
Technical nameproject_task_progressbar
Field typesfloat (a 0 to 1 fraction), integer
Viewslist, form
Also registered asalso in the formatters registry (percentage formatting for aggregations)
Modulehr_timesheet (Timesheets)
Used in core5 occurrences across 1 module: task lists and task sharing views in hr_timesheet
VersionsOdoo 20.0, Odoo 19.0, Odoo 18.0, Odoo 17.0
No-code setupNo: it is wired to the task progress field in XML
Alternativesprogressbar, percentage, percentpie

What the Task Progress Bar widget does

When a project task has allocated hours, Odoo computes progress as hours spent divided by hours allocated, a fraction between 0 and beyond 1 for overruns. project_task_progressbar is the widget that renders that fraction in task lists, and it makes two opinionated changes to the standard progress bar it extends.

It rescales. The base widget displays raw values; this one overrides currentValue to multiply by 100, so a stored 0.45 renders a 45 percent bar. That keeps the model's convention (fractions, which the decoration-danger="progress >= 1" conditions elsewhere in the views rely on) while displaying percentages.

It self-colors. The base bar is primary blue until overflow. This one is green below 80, orange from 80 to the maximum, and hands overruns to the inherited overflow class, which core's task views set to bg-danger. The result is the classic traffic light: comfortable, at risk, over budget.

A quiet third change: the file registers project_task_progressbar in the formatters registry as a percentage formatter, so the same field aggregated in a pivot or grouped list also prints as a percentage rather than a decimal.

What this means for your team

For services companies, this bar is the earliest budget-overrun alarm that requires zero process.

A project manager scrolling the task list is not reading numbers; they are scanning for orange and red. Orange at 80 percent is the actionable moment, enough budget left to rescope, reassign or renegotiate, and that 80 percent threshold is the widget's real product decision. Red only confirms what already went wrong.

Two implementation notes from our projects. First, the bar only appears when tasks have allocated hours; teams that skip estimation get an empty column and blame the tool, so the rollout conversation is about estimating discipline, not XML. Second, the thresholds are hardcoded in the widget: if your risk appetite says orange at 60 percent, that is a five-line JavaScript override, not an option, and worth it for fixed-price work.

Supported options in Odoo 19

Verified against project_task_progress_bar_field.js in the Odoo 19.0 hr_timesheet module, which spreads the full progressBarField descriptor from web. The options below are inherited from progressbar and verified there; the notes flag how the x100 override interacts with them.

OptionTypeWhat it does
overflow_classstringInherited. Bootstrap class applied when the value exceeds the maximum. Core's task views pass bg-danger, which is where the red comes from; omitted, overruns render gray.(default: bg-secondary)
max_valuefield name (integer/float)Inherited. A field holding the bar's maximum, displayed next to the bar when set. On this widget remember the comparison uses the x100-scaled current value.(default: 100)
current_valuefield name (integer/float)Inherited. Displays a different field's value on the bar than the one the widget is placed on. The x100 override applies to whichever field is displayed.
editablebooleanInherited, but hazardous here: the display is scaled x100 while the parser writes raw input back, so typing the displayed number stores 100 times the intended fraction. Core never enables it on this widget.
edit_max_valuebooleanInherited. With editable, switches editing to the max value field instead of the current value.

Think twice before setting editable on this widget. The display multiplies by 100 but the inherited parser does not divide back: the input shows 45, and a user retyping 45 would store 45, not 0.45. Core never enables editing here, and neither should you; edit the underlying hours, not the computed fraction.

Working examples

As the task list uses it

<field name="progress" widget="project_task_progressbar" optional="hide"
       options="{'overflow_class': 'bg-danger'}"
       groups="hr_timesheet.group_hr_timesheet_user"/>

Green under 80, orange to 100, red past it. The column ships hidden behind the optional toggle.

On your own fraction field

budget_used = fields.Float(compute="_compute_budget_used")  # stores 0.0 to 1.0+
<field name="budget_used" widget="project_task_progressbar"
       options="{'overflow_class': 'bg-danger'}"/>

Any 0 to 1 fraction gets the same traffic-light treatment; hr_timesheet must be installed.

Reading the threshold logic exactly

The color getter rewards precise reading:

get progressBarColorClass() {
    if (this.currentValue > this.maxValue) {
        return super.progressBarColorClass;
    }
    return this.currentValue < 80 ? "bg-success" : "bg-warning";
}

The comparison runs on the scaled value. currentValue is already x100 here, and maxValue defaults to 100 when no max_value option is set. So the boundaries are: exactly 80 is already orange (the test is strictly less than 80), exactly 100 is still orange, and only past 100 does the super call return the overflow class.

The overflow color is inherited, not hardcoded. The super getter returns overflowClass, defaulting to bg-secondary gray; the red everyone associates with this bar comes from core's views passing overflow_class: bg-danger. Omit the option and your overruns render gray.

The formatter registration is easy to miss and easy to want. registry.category("formatters").add("project_task_progressbar", formatPercentage) means widget="project_task_progressbar" on a pivot or graph measure formats the fraction as a percentage too, the same dual-registry trick as im_livechat.rating_percentage, but this widget lives in both registries at once.

Version compatibility

VersionStatusNotes
Odoo 20.0In developmentNot released. This file is byte-identical on the development branch, but the base progressbar it spreads loses options there; see below.
Odoo 19.0VerifiedVerified against the shipped source; byte-identical to 18.0.
Odoo 18.0VerifiedAdds the x100 scaling and the percentage formatter registration.
Odoo 17.0Partial / changedExists with threshold colors but without the x100 scaling or formatter; displays the raw fraction.
Odoo 16.0Not availableDoes not exist.

Upgrade note. In Odoo 17 the widget existed without the x100 scaling and without the formatter registration; it displayed the raw fraction and relied on the surrounding view for percentage semantics. From 18 the scaling is built in, so custom views that pre-multiplied their field by 100 for 17 will display 10,000-style values after upgrading: store fractions and let the widget scale.

What is changing in Odoo 20

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

No changes: the source file on master is byte-identical to Odoo 19, thresholds, scaling and formatter registration included. Watch the base progressbar page instead: on the development branch the base widget loses most of its options, and since this widget spreads the base descriptor, those removals will flow through to it at release. We re-verify against the shipped release.

Common problems and fixes

SymptomCause and fix
The bar shows 4500% or similarThe field stores percentages (45) while the widget multiplies by 100 expecting fractions (0.45). Store the fraction in the field; the widget owns the scaling since Odoo 18.
The bar column is empty for most tasksProgress computes from allocated hours; tasks without an estimate have nothing to divide by. Set allocated hours on tasks (and make estimation part of the team's definition of ready).
Overruns show gray instead of redThe overflow class defaults to bg-secondary; the red in core comes from the view passing overflow_class. Add options="{'overflow_class': 'bg-danger'}" on the field.
You need orange to start at 60 instead of 80The 80 and 100 thresholds are hardcoded in the color getter. Extend the widget in JavaScript and override progressBarColorClass; it is a five-line patch.
Editing the bar writes absurd valuesThe editable option round-trips asymmetrically on this widget: display is x100, the parser is not. Keep the bar read-only and let users edit the underlying hours fields instead.
Missing widget warning outside project contextsThe widget ships with hr_timesheet. Add hr_timesheet as a dependency or fork the small widget into your module.

Task Progress Bar widget vs the alternatives

WidgetBest forKey difference
project_task_progressbarA 0 to 1 fraction that should traffic-light itself at 80 and 100 percentMultiplies by 100 for display and hardcodes green, orange, then overflow coloring
progressbarProgress against a real max field, values already scaledNo scaling, primary blue until overflow, optionally editable
percentageShowing the same fraction as a compact numberFormats fractions as percent text; no bar, no thresholds
percentpieA circular gauge on dashboard-style viewsExpects 0 to 100 values, the opposite scaling convention from this widget

Use this widget when the field is a 0 to 1 fraction and risk thresholds should color it. For values already on a 0 to 100 scale with a real max field, the base progressbar is the honest choice; for a compact circular snapshot, percentpie.

Frequently asked questions

When does the Odoo task progress bar turn orange and red?+
Orange from 80 percent (the source tests strictly below 80 for green), and the overflow color, red in core's views, only past 100 percent. Exactly 100 percent is still orange.
Why does my custom field render a 4500% bar?+
The widget multiplies by 100 because core's progress field stores fractions. Store 0.45 for 45 percent; if your field already stores 45, use the base progressbar widget instead.
Can I change the 80 percent threshold?+
Not by options; both thresholds are hardcoded in the color getter. A small JavaScript extension overriding progressBarColorClass is the supported route.
Why is my overrun gray instead of red?+
Red is not built in: core's views pass options="{'overflow_class': 'bg-danger'}". Without that option the inherited default is bg-secondary.
Does the bar work in pivots too?+
The widget also registers a percentage formatter under the same name, so widget="project_task_progressbar" on a pivot measure formats the fraction as a percentage. The bar itself renders in list and form views.
Why is the progress column empty on my tasks?+
The underlying progress field divides hours spent by allocated hours; without allocated hours there is no fraction to show. Estimate tasks and the bars appear.

Projects that warn you at 80 percent, not 120?

The bar only works if timesheets are filled, tasks are estimated, and managers trust the numbers. We roll out Odoo Project and Timesheets with the habits attached: estimation flows, approval chains and the reports that catch overruns while there is still budget to act.

Get our timesheets under control

How this page was produced

This page was verified by reading project_task_progress_bar_field.js in the Odoo 19.0 hr_timesheet module together with the base progress_bar_field.js in web whose descriptor it spreads, including the strict-inequality thresholds, the inherited overflow class and the round-trip asymmetry under the editable option. The 17-to-18 scaling change was confirmed by diffing the file across the 17.0, 18.0, 19.0 and master branches; the usage example is quoted from the shipped task views. Spotted an error or a version difference? Tell us and we will correct the page.