2025, Dec 25 21:00

Odoo List View Header Button Missing? It Shows Only on Selection—Here’s Why and How to Keep It Visible

Learn why Odoo list (tree) view header buttons hide until records are selected, how to trigger server actions, and using Owl JS to keep the button visible.

When you add a button to the header of an Odoo list (tree) view and it refuses to show up, it’s tempting to suspect broken XML or a missing model method. In reality, the UI behavior often explains everything: header buttons in list views usually appear only when at least one record is selected.

Reproducing the situation

The following example defines a custom list view for product.product with a header button and a matching server-side method. The logic is correct; the confusion comes from how Odoo decides when to show the button.

<?xml version="1.0" encoding="utf-8"?>
<odoo>
  <record id="view_item_list_custom" model="ir.ui.view">
    <field name="name">"electronic.product.view.alt"</field>
    <field name="model">product.product</field>
    <field name="priority" eval="99"/>
    <field name="arch" type="xml">
      <list>
        <header>
          <button name="action_launch_import" string="import" type="object"/>
        </header>
        <field name="name" string="product name"/>
        <field name="volume" string="quantity"/>
        <field name="x_product_url" string="quantity"/>
      </list>
    </field>
  </record>
  <record id="action_electronic_products_alt" model="ir.actions.act_window">
    <field name="name">Electronic Products</field>
    <field name="res_model">product.product</field>
    <field name="view_mode">list</field>
    <field name="view_id" ref="view_item_list_custom"/>
  </record>
  <menuitem id="menu_electronic_product_root_alt" name="Electronic Products" action="action_electronic_products_alt" sequence="10" groups="base.group_user"/>
</odoo>
from odoo import models, fields, api

class CatalogProduct(models.Model):
    _inherit = 'product.product'

    x_product_url = fields.Char(
        string='Product Link',
        help='URL of the product',
        default='',
        tracking=True
    )

    def action_launch_import(self):
        return {
            'name': 'Import Products',
            'type': 'ir.actions.act_window',
            'res_model': 'product.import.wizard',
            'view_mode': 'form',
            'target': 'new',
            'context': {'default_product_id': self.id},
        }

What’s really happening

The XML and Python above are functionally correct. In Odoo, buttons placed in the header of a tree/list view do not always render by default. They become visible when records are selected in the list. With no selection, the header button can disappear, which looks like a rendering problem but is actually expected behavior.

How to make it work

To verify that everything is wired correctly, open the list view and select one or more rows. The header button appears, and clicking it will trigger the server-side method, opening the intended wizard. If the requirement is to keep the button visible at all times, that calls for additional UI customization using the Owl JS component. This approach is more advanced and goes beyond simple XML view definitions. A related discussion that explores placing a button next to Create in a list view is available here: https://www.odoo.com/ro_RO/forum/suport-1/how-to-add-a-button-next-to-create-in-list-view-in-odoo-16-219508.

Why this matters

Understanding how Odoo renders actions in list headers prevents misdiagnosing a healthy view as broken. It saves time you might otherwise spend rewriting XML or renaming methods that were correct from the start. It also clarifies when you need standard backend actions versus when you have to reach for front-end customization with Owl to alter default UI behavior.

Takeaways

If a header button in a list view seems missing, first select a record to confirm whether it’s simply hidden by design. When the feature must be always visible, plan for a front-end extension via Owl JS. The backend snippet above is valid as-is; the key is aligning expectations with how Odoo shows list-level actions and knowing when a UI-layer change is required.