Skip to main content
iVentureTeam

many2many_checkboxes

The Checkboxes field lists every record of a relation as a tickbox: no search, no create, the whole choice space visible at once. Ideal for short fixed sets like product routes.

Siddharth JambukiyaSiddharth JambukiyaOdoo Techno-Functional Consultant
August 16, 2026Updated August 16, 20266 min read
Odoo 19 product form Inventory tab where the many2many_checkboxes widget renders the Routes field as tickboxes for Replenish on Order (MTO) and Dropship, both checked.
Studio nameCheckboxes
Technical namemany2many_checkboxes
Field typesmany2many
Viewsform
Moduleweb, present in every Odoo database
Used in core8 occurrences across 5 modules, including lunch, stock, website, account_edi, event_booth_sale
VersionsOdoo 20.0, Odoo 19.0, Odoo 18.0, Odoo 17.0, Odoo 16.0
No-code setupYes, via Odoo Studio (Enterprise)
Alternativesmany2many_tags, radio, many2many_tags_avatar, one2many

What the Checkboxes field does

Tags and dropdowns hide the options a user did not pick. For some decisions that is wrong: choosing warehouse routes on a product, meal categories on a lunch supplier, or EDI formats on a journal is a decision about the whole set, and the user should see every possibility while making it. The many2many_checkboxes widget renders exactly that: every record of the related model that matches the field's domain, as a checkbox list, ticked where a link exists.

There is no search box, no "create", no pagination. That austerity is the design: the widget assumes the choice space is small and stable, and in exchange the user gets the complete picture in one glance.

What this means for your team

The checkbox presentation changes user behavior in a way worth exploiting. With tags, users pick what they remember exists; with checkboxes, they audit the full list every time. For configuration-flavored choices, which routes, which document types, which booth options, that audit moment prevents the "nobody knew that option existed" class of misconfiguration entirely.

The flip side is a hard scaling rule. The widget loads every candidate up front and silently shows at most 100, so it belongs on relations that stay small by nature. Our sizing rule from implementations: a dozen options is ideal, thirty is tolerable on a wide form, beyond that switch to tags and let search do the work. If the option list is user-extensible, it will not stay small, and checkboxes are the wrong bet.

Setting it up in Odoo Studio (no code)

This is one of the widgets Studio exposes cleanly.

  1. Open the form in Studio and select an existing many2many field, or drag a Many2Many field onto the layout and pick the related model.

  2. Open Properties on the right and set Widget to Checkboxes.

  3. Optionally set a Domain in the same panel to trim which records appear as boxes, for example only active ones.

What Studio cannot do here

What Studio configures here is nearly everything the widget can do, because the widget itself is optionless. The limits are the widget's own: no way to enable search or creation, no way to raise the 100-record cap, no columns or grouping control for long lists, and no one2many support at all. If any of those are requirements, the fix is a different widget or a custom one, not more configuration.

Working examples

Product routes, as core ships it

<field name="route_ids" widget="many2many_checkboxes"/>

Trimmed to relevant options with a domain

<field name="category_ids"
       widget="many2many_checkboxes"
       domain="[('active', '=', True), ('company_id', 'in', [company_id, False])]"/>

Only active, company-relevant records render as boxes. The same domain keeps the candidate count under the cap.

Defaults for records created from the list

<field name="tag_ids"
       widget="many2many_checkboxes"
       context="{'lang_filter': 'en'}"/>

The context is passed into the record-loading call, useful when the related model's name_search behaves contextually. The widget itself never creates records.

The 100-record cap and the 500ms batch window

Two implementation choices explain the widget's feel in daily use.

The 100-record ceiling is inherited, not chosen. The list is fetched with name_search("", domain) and no limit argument, so Python's default limit=100 applies. Records beyond it are not rendered, with no indicator that anything is missing. If users report a checkbox "disappearing", count the candidates first.

Changes are batched deliberately. Each tick goes into a pending add or remove set, and a 500ms debounced commit folds them into one addAndRemove call. The component also commits on unmount and when the record model demands local changes, so nothing is lost by clicking Save quickly. The payoff is fewer onchange recomputations on models with heavy onchange logic, which is exactly the configuration-model territory this widget lives in.

A last detail: isEmpty is hardcoded false, so the widget always renders its list even when nothing is ticked. An empty checkbox list on the form means the domain matched no records at all.

Version compatibility

VersionStatusNotes
Odoo 20.0In developmentNot released. Behavior preserved on the development branch over new RPC plumbing; details below.
Odoo 19.0VerifiedVerified against the shipped source and tested on a clean database.
Odoo 18.0VerifiedByte-identical component to 19.0.
Odoo 17.0VerifiedSame behavior and absence of options.
Odoo 16.0VerifiedAvailable with the same rendering; the widget predates the current web client.

Upgrade note. The 18.0 and 19.0 components are byte-identical, and the widget has behaved this way for years. Views carry across upgrades untouched; only the Odoo 20 internals change, without affecting XML.

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, which is unstable until feature freeze; we re-verify this page after release.

The widget's contract survives, its plumbing does not. The load moves from name_search to the newer web_name_search RPC with an explicit display-name specification, and it gains offline resilience: on a lost connection it falls back to rendering the records already linked instead of erroring. The batched commit switches from an add-and-remove call to explicit link and unlink commands that carry display names, and the widget starts declaring display_name in relatedFields.

Nothing option-related changes, because there are still no options. The 100-record behavior depends on the new RPC's server-side default; we will verify the effective cap against the release.

Common problems and fixes

SymptomCause and fix
Some records never appear as checkboxesThe list is capped at 100 records by the ORM's default name_search limit, with no visual hint. Tighten the field's domain, or switch to many2many_tags for large sets.
The widget shows nothing at allThe domain matched no records; the widget still renders, just empty. Check the domain and the related model's active records.
Users cannot add a new option from the fieldThe widget has no creation path by design. Create the record in its own model first, or use a tags widget where quick-create fits.
Used on a one2many field, nothing renders correctlySupported types are many2many only. Use the one2many list widget or restructure the relation.
Onchange logic seems to lag behind the clicksChanges are debounced for 500ms and committed as one batch. Expected; the batch commits before saving, on unmount and on demand.
Boxes are unticked after checking them and switching records fastInterrupting the debounce window in older customized builds; core commits on unmount. Verify no custom patch removed the unmount commit; core behavior is safe.

Checkboxes field vs the alternatives

WidgetBest forKey difference
many2many_checkboxesShort, fixed option sets the user should see in fullEvery candidate rendered, no search, no create, capped at 100
many2many_tagsLong or user-extensible listsSearch-based pills with optional creation and colors
radioChoosing exactly one option, all visibleSingle choice on selection or many2one fields
many2many_tags_avatarPicking people rather than optionsAvatar pills with search, better for user sets
one2manyRelations whose records carry data worth seeing in columnsFull grid, supports one2many

The decision rule we give clients: if the user must see what they are not choosing, checkboxes; if the user knows what they want and the list is long, tags; if only one choice is allowed, radio.

Frequently asked questions

What does many2many_checkboxes do in Odoo?+
It renders a many2many field as a checkbox list of every related record matching the field's domain, ticked where a link exists. Users tick and untick to link and unlink; nothing else is offered, by design.
How many records can the checkboxes widget show?+
Effectively 100. The widget loads candidates with a limit-less name_search, so the ORM's default cap of 100 applies and anything beyond it is silently not rendered. Keep the domain tight or use tags for bigger sets.
Can users create new records from the checkbox list?+
No. The widget has no creation flow at all. Records must exist in the related model first; if inline creation matters, many2many_tags offers it.
How do I set up checkboxes in Odoo Studio?+
Select or add a many2many field in Studio, open Properties, and set Widget to Checkboxes. A domain in the same panel controls which records appear as boxes.
Why does Odoo wait a moment before reacting to my ticks?+
Ticks are collected for 500ms and committed as one batched change, so checking several boxes triggers a single onchange round trip. The batch always commits before a save, so no clicks are lost.
Does many2many_checkboxes work on one2many fields?+
No. Its supported types list is strictly many2many. For one2many relations use the standard list widget, or rethink whether the relation should be many2many.
Anything changing in Odoo 20 for this widget?+
The development branch swaps the loading RPC for web_name_search, adds an offline fallback to already-linked records, and rewrites the batch commit as explicit link and unlink commands. User-visible behavior and the empty option surface stay the same; we re-verify once Odoo 20 ships in late September 2026.

Forms your users configure at a glance?

Picking the right widget per field is cheap; living with the wrong one is not. We refine Odoo forms field by field, from route and compliance checklists to fully custom selection widgets when the standard ten are not enough.

Refine your Odoo forms

How this page was produced

This page was verified by reading many2many_checkboxes_field.js on the Odoo 19.0 branch, confirming byte-identity with 18.0, and diffing the development branch for the RPC and command changes. The 100-record cap was traced to the limit-less name_search call against the ORM default. The screenshot is the product routes field on a clean Odoo 19 database. Corrections welcome via our contact page.