background_image
The large employee photo panel in Odoo HR is not the standard image widget: background_image inherits every image option but swaps the template for a bare, display-only <img> with no upload or delete controls.
| Technical name | background_image |
|---|---|
| Field types | binary, many2one (inherited from the image field) |
| Views | form, kanban |
| Module | hr (Employees) |
| Used in core | 6 occurrences across 2 modules, including hr and hr_org_chart, on employee photos |
| Versions | Odoo 20.0, Odoo 19.0, Odoo 18.0, Odoo 17.0, Odoo 16.0 |
| No-code setup | No: applying it to a field is an XML-only change |
| Alternatives | image, image_url, many2one_avatar_employee |
What the Background Image widget does
What this means for your team
Supported options in Odoo 19
| Option | Type | What it does |
|---|---|---|
preview_image | field name (binary) | Inherited. Serves this field's smaller variant (e.g. image_128) as the displayed source instead of the full stored image. Mandatory when the widget is placed on a many2one field. |
zoom | boolean | Inherited. Shows the full image in a hover tooltip. Core's employee form enables it so the small panel can reveal the full photo. |
zoom_delay | number (ms) | Inherited. Milliseconds before the zoom tooltip appears; the employee form uses 1000. |
size | selection [width, height] | Inherited. Max-width/max-height constraints ([0,90], [0,180], [0,270] in Studio terms) applied as inline style limits. |
reload | boolean | Inherited. When false, the widget keeps serving the first URL it computed instead of following value changes.(default: true) |
convert_to_webp | boolean | Inherited but inert here: it acts during upload, and this widget's template provides no upload path. |
accepted_file_extensions | string | Inherited but inert here for the same reason: no file picker is ever opened from this widget.(default: image/*) |
img_class | string (undocumented) | Inherited from the image widget's extractProps, where it is read but declared nowhere. Inert under this template, which does not apply imgClass; use the class attribute on the field element instead. |
Inherited does not mean usable. The descriptor accepts all image options, but the template has no upload path, so convert_to_webp and accepted_file_extensions can never trigger, and the alt attribute is accepted but the template hardcodes alt="Binary file". The options that actually change what you see are zoom, zoom_delay, preview_image, size and reload.
Working examples
What it inherits, including the sharp edges
Version compatibility
| Version | Status | Notes |
|---|---|---|
| Odoo 20.0 | In development | Not released. The source file on the development branch is byte-identical to 19.0. |
| Odoo 19.0 | Verified | Verified against the shipped source. |
| Odoo 18.0 | Verified | Identical wrapper apart from the module pragma line. |
| Odoo 17.0 | Verified | Present and functionally identical. |
| Odoo 16.0 | Verified | Present with the older class-assignment syntax; same behavior. |
Upgrade note. The widget has been a five-line wrapper since Odoo 16; only the wrapper syntax modernized (class fields in 19 versus assignment style in 16). XML using it carries across versions untouched.
What is changing in Odoo 20
Common problems and fixes
| Symptom | Cause and fix |
|---|---|
| Users cannot change the photo from this widget | By design: the template is a bare img with no upload or delete controls. Edit the image through the standard image widget elsewhere in the view (the avatar field on employees). |
| The view crashes when the widget sits on a many2one field | The inherited image logic throws unless preview_image names the image field on the target model. Add options="{'preview_image': 'image_128'}" (or the relevant field) to the widget. |
| An empty field shows a gray placeholder silhouette | The inherited URL fallback serves /web/static/img/placeholder.png when the value is empty. Hide the field with an invisible condition when empty if the placeholder is unwanted. |
| The image looks stretched or overflows its panel | The widget applies no background sizing itself; the framing comes from surrounding classes. Add sizing classes on the field element (as core does with d-block position-relative) or the size option. |
| An updated image does not refresh on a related field | The write_date cache key is skipped when the image lives on another record, an inherited behavior. Display the image from its own record where possible, or accept a refresh delay. |
Background Image widget vs the alternatives
| Widget | Best for | Key difference |
|---|---|---|
background_image | Showing an image users must not edit in place | Full image option set with the upload and delete controls removed |
| image | Images users upload and manage | Same engine plus the upload, edit and delete controls and WebP pipeline |
image_url | Images hosted outside Odoo | Renders from a URL in a char field; nothing is stored in the database |
| many2one_avatar_employee | A small employee photo next to their name | Avatar chip on a relational field, not a display panel |
Frequently asked questions
Why can't I upload a photo through the big image on the employee form?+
What is the difference between background_image and image?+
Can I use background_image outside HR?+
Does it support zooming into the image?+
Why does it load a small image first?+
Views that show exactly what each role should touch?
Display-only images, locked fields and role-shaped forms are how an Odoo becomes safe to hand to a whole company. We take that discipline through your views screen by screen, deciding per role what is visible, what is editable, and what loads fast.
Shape our views by role