Odoo Development · intermediate · 11 min read
Views, Menus, and Actions
Building and inheriting Odoo UI: form, list, kanban, search views, xpath, window actions, menus, and client-side patterns for Odoo 16/17.
Last reviewed 2026-07-30 · Estimated effort: 2–6 weeks typical implementation slice
Table of contents
Views are XML definitions compiled into client descriptions. Menus point to actions — usually ir.actions.act_window — which open models in form, list, kanban, or graph mode with domains and contexts.
Inheritance via xpath (//field[@name='partner_id'] position="after") is the upgrade-friendly way to extend UI. Copy-pasting full core views breaks on the next Odoo minor when structure shifts.
Security groups on menus and views hide UI; they do not replace ACL. attrs/invisible rules in Odoo 17 still exist but Studio and OWL favor modifiers — know your target version syntax.
Users experience your module through menus and views, not Python files. Sloppy xpath or missing action domains creates support noise that no amount of backend logic fixes.
This article covers view types, inheritance mechanics, action/context patterns, and how menus wire into the app shell.
Form views layout fields, notebooks, buttons, and smart buttons. List (tree) views drive bulk editing and exports. Search views define filters, group-by, and search fields. Kanban, calendar, graph, and pivot serve operational and analytic use cases.
Each view record binds to a model via model= attribute. Priority controls which view wins when multiple apply — lower number is higher priority for inheritance chains.
- ▸tree editable="bottom" for inline line editing
- ▸widget= on fields (many2many_tags, statusbar, monetary)
- ▸create="0" delete="0" on list to restrict inline CRUD
Extend with <record id="view_sale_order_form_inherit" model="ir.ui.view"> inheriting ref="sale.view_order_form". Use xpath expr with position inside, after, before, replace, attributes.
Prefer stable anchors — field names, named groups — over positional indexes. After Odoo upgrades, run -u and open affected forms to catch xpath misses early.
act_window sets res_model, view_mode (list,form,kanban), domain, context, and optional view_ids. Context defaults (default_type, search_default_*) shape out-of-box filters.
Server actions and automated actions can return act_window dicts from Python — keep domains parameterized, not string-concatenated SQL fragments.
menuitem nests under parent menus with sequence ordering. groups= on menuitem limits visibility to security groups. Root menus often set web_icon for app switcher branding.
Separate configuration menus from daily operations — operators should not hunt through Settings for routine tasks.
Odoo 17 web client uses OWL components. Extend via assets in __manifest__.py — patch list controllers or add systray items sparingly. Prefer server-side fields and standard widgets before custom JS.
QWeb reports live under report/ with paperformat records — distinct from backend form views but still XML-driven.
- ✓One inherit view per concern — approval fields vs logistics fields in separate XML files.
- ✓Name external ids with module prefix to avoid cross-module collisions.
- ✓Test mobile layouts for warehouse and field service forms.
- ✓Use domain on actions to pre-filter data — not only search defaults.
- ✓Document smart button domains in module README for functional teams.
- ✓Run view validation on CI with --test-enable or odoo-bin shell smoke tests.
- !xpath position="replace" on fields Odoo renamed in upgrade.
- !Duplicating entire sale.view_order_form into custom module.
- !Relying on menu groups alone without model ACL.
- !Hard-coded company ids in action domains.
- !Mixing attrs syntax from different Odoo versions in one project.
- !Forgetting to add inherited views to __manifest__.py data list.
Views and menus are the product surface. Inherit surgically, test after every platform upgrade, and keep actions aligned with record rules.
Security groups and record rules determine whether those screens expose data users should not see — even if the menu is hidden.
Trigger
Business event starts the flow.
Execute
Operate in the system of record.
Validate
Check outcomes and exceptions.
Close
Reconcile and hand off.
__manifest__.py
models/
views/
security/
data/
- manifestmodels
- modelsviews
- modelssec
Frequently asked questions
What happens when xpath matches nothing?
Install or upgrade may fail with XPath not found, or silently skip depending on settings. Always test -u on staging after core upgrades.
How do I add a button that calls Python?
Define type="object" button with name matching a public model method. Use confirm= for destructive ops. type="action" opens another act_window.
Can one menu open multiple models?
Each menuitem links to one action. Use server actions or client wizards to branch if needed — avoid confusing operators.
Studio vs XML views — which wins?
Higher priority view records win. Studio often creates lower-priority inherits — but document Studio layers before merging into Git modules.
Related articles
Understanding Odoo Module Structure
How Odoo addons are laid out: manifests, models, views, security, data, and dependency order — the foundation every developer ticket should respect.
View →Security: Groups and Record Rules
Odoo access rights: ir.model.access.csv, security groups, record rules, field-level restrictions, and multi-company patterns that enforce server-side.
View →How the Odoo ORM Works
Environments, recordsets, transactions, prefetch, and the create/write/unlink lifecycle — practical ORM behavior for Odoo 16/17 developers.
View →Deployment Best Practices
Shipping Odoo modules safely: staging parity, -u vs -i, backups, zero-downtime limits, workers, logging, and rollback playbooks for on-prem and Odoo.sh.
View →Broken views after an Odoo upgrade?
We repair xpath inherits, rationalize menus, and align UI with restored security boundaries.
