Skip to main content
iVentureTeam

radio

The radio widget lays every choice of a selection or many2one field out as radio buttons, so users see all options before picking one.

August 11, 2026Updated August 11, 20266 min read
Odoo 19 product attribute form showing the radio widget rendering display type choices as a vertical list of radio buttons.
Studio nameRadio
Technical nameradio
Field typesselection, many2one
Viewsform, list (editable), settings
Moduleweb, present in every Odoo database
Used in core151 occurrences across 56 modules, including website_sale, hr_holidays, account, product, stock, survey
VersionsOdoo 20.0, Odoo 19.0, Odoo 18.0, Odoo 17.0, Odoo 16.0
No-code setupYes, via Odoo Studio (Enterprise)
Alternativesselection, selection_badge, priority, statusbar

What the radio widget does

A dropdown hides its choices until clicked; a radio list shows them all, always. That is the whole trade this widget makes: more vertical space in exchange for zero clicks to see what the options are.

It accepts two field types, and behaves slightly differently on each, straight from the source. On a selection field the choices come from the field definition, no query needed. On a many2one the widget fetches the related records with a web_search_read call, applying the field's domain, and lists one button per record found.

Odoo's own forms use it wherever the choice shapes everything below it: a product attribute's display type, a leave type's request unit, payment provider states. Seeing all options at once is what makes those forms self-explanatory.

What this means for your team

Radio buttons are a forcing function for clarity. When the options are visible, users notice choices they would never open a dropdown to discover, and mis-picks drop. For fields where the wrong value quietly changes behavior, how a product displays on the website, how time off is counted, visible options are cheap insurance.

The same visibility disciplines your configuration. A dropdown swallows twenty options; a radio list makes twenty options look as absurd as they are. If the radio rendering of a field feels overwhelming, the field has too many choices, and that is worth knowing before users meet it.

Our rule on implementations: radio for 2 to 5 stable, mutually exclusive choices a user must understand; dropdown for anything longer or frequently extended. The widget swap is one attribute either way, so there is no cost to getting it right per field.

Setting it up in Odoo Studio (no code)

Studio applies this widget without code.

  1. Open the form in Studio and select the selection or many2one field.

  2. In Properties, set Widget to Radio.

  3. For a horizontal row instead of a vertical column, tick the Display horizontally option Studio shows for this widget.

What Studio cannot do here

Two things stay in XML territory.

Filtering which records appear for a many2one, only active carriers, only company-scoped values, is the field's domain attribute.

Conditional choices, where the options depend on another field on the form, need a dynamic domain, which is developer work.

Supported options in Odoo 19

Verified against radio_field.js in the Odoo 19.0 web module. The widget declares exactly one option; orientation is the only knob it has.

OptionTypeWhat it does
horizontalbooleanLays the radio buttons out in a row instead of the default vertical column. That is the widget's entire option surface, verified in the source.

There is no creation path, and that is a feature. A many2one rendered as radio buttons offers no Create entry, no quick-create from typed text, nothing. Where a dropdown needs no_create bolted on to lock a taxonomy, the radio widget is closed by construction. If users must also add records, keep the dropdown.

Working examples

Selection field as radio buttons

<field name="display_type" widget="radio"/>

Vertical list, one button per selection value, in the order the selection declares them.

Horizontal row

<field name="request_unit"
       widget="radio"
       options="{'horizontal': True}"/>

Same buttons in a row. Works best for two or three short labels; longer sets wrap awkwardly on narrow screens.

Many2one with a filtered record list

<field name="carrier_id"
       widget="radio"
       domain="[('active','=',True), ('website_published','=',True)]"/>

One button per matching carrier. The widget merges this domain into its record fetch, so the buttons always reflect current data.

How the record list is really loaded

On many2one fields the widget's record loading has consequences the source makes explicit.

It loads everything the domain allows. The web_search_read behind the buttons has no practical limit; a thousand matching records means a thousand radio buttons. The widget is only as sensible as the domain you give it, so treat the domain as required on any model that grows.

The list is fetched per form load. New records appear as buttons the next time the form renders. There is no caching layer to go stale, but also a query on every open, another reason to keep the domain tight.

Unselecting is not a thing. Radio semantics allow switching, never clearing. If blank must be a legal state, either add an explicit "None" selection value or stay with a dropdown, which can be cleared.

Version compatibility

VersionStatusNotes
Odoo 20.0In developmentNot released. Options unchanged in the development branch; loading gains offline resilience. See below.
Odoo 19.0VerifiedVerified against the shipped source and tested on a clean database.
Odoo 18.0VerifiedSame option and behavior. No XML changes needed.
Odoo 17.0VerifiedSame option and behavior. No XML changes needed.
Odoo 16.0VerifiedSame option and behavior. No XML changes needed.

Upgrade note. The single horizontal option and both supported types are unchanged from Odoo 16 through 19, so views migrate untouched. Only JavaScript patches on the component need review, as its internals moved to hooks over the versions.

What is changing in Odoo 20

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

Options and types are unchanged: horizontal remains the only option, on the same two field types, so existing views carry over untouched.

Two behavior refinements appear. The many2one record fetch now survives connection loss: on a ConnectionLostError the widget falls back to showing the currently selected record instead of erroring, part of Odoo 20's broader offline hardening. And the component detects touch devices to adjust its rendering. Neither requires any view change; we re-verify this page once Odoo 20 ships.

Common problems and fixes

SymptomCause and fix
Way too many radio buttons renderThe many2one has no domain, so every record of the related model becomes a button. Add a domain to the field, or switch to a dropdown for open-ended models.
A choice is missing from the buttonsThe field's domain or a record rule excludes that record, or it is archived. Check the domain and the record's active flag; test as admin without the domain.
Users cannot clear the fieldRadio semantics never unselect by design. Add an explicit none/empty choice, or use a dropdown if blank is a legal state.
Horizontal row wraps badly on small screensToo many or too long labels for a row layout. Drop the horizontal option or shorten the labels; vertical is the safer default past three choices.
Users expect to add a new record from the buttonsThe widget has no creation path at all. That is by design; use a dropdown (many2one) when users must create records inline.

Radio widget vs the alternatives

WidgetBest forKey difference
radio2 to 5 mutually exclusive choices users should see at onceAll options always visible; no search, no creation
selectionLonger or rarely-inspected choice listsDropdown: compact, searchable on many2one, clearable
selection_badgeThe same visible-choices idea with a button lookRenders choices as clickable badges rather than radio circles
priorityRanked levels like priority or ratingStars communicate ordering, not arbitrary categories
statusbarWorkflow stagesLives in the form header and represents process position

The practical test: if seeing every option teaches the user something, radio. If the user already knows what they want and the list is long or user-extensible, dropdown. If the choice is a workflow state, use the statusbar and stop overloading a field widget with process semantics.

Frequently asked questions

How do I show a selection field as radio buttons in Odoo?+
Set widget="radio" on the field in the view, or in Studio select the field and choose the Radio widget. Works on selection and many2one fields.
How do I make Odoo radio buttons horizontal?+
Add options="{'horizontal': True}" to the field. It is the widget's only option, verified against the Odoo 19 source.
Can users create a new record from a radio widget?+
No. Unlike the many2one dropdown, the radio widget has no create or quick-create path at all. If inline creation matters, keep the dropdown.
How do I limit which records appear as radio buttons?+
Put a domain on the field; the widget merges it into the web_search_read it uses to load the buttons. Without a domain, every record of the model becomes a button.
Why does my radio field slow the form down?+
On a many2one the widget fetches all matching records each time the form loads. A large related model with no domain means a large query and a wall of buttons; tighten the domain or use a dropdown.
Radio or selection_badge, which should I use?+
They solve the same visibility problem with different looks. Radio reads as a form control and suits settings-style pages; selection_badge reads as buttons and suits fast repeated picking. Behavior differences are minor; pick by context.

Forms your team fills without thinking twice?

Choosing the right control per field, radio here, dropdown there, badges where speed matters, is exactly the kind of UX pass we run over Odoo forms during customization work on Odoo 16 through 19.

Book a free consultation

How this page was produced

The option table and both field-type behaviors were read from the Odoo 19.0 web module source (radio_field.js), including the web_search_read record loading and the domain handling, and confirmed on a clean Odoo 19 database, where the screenshot was captured. Studio steps were performed on an Odoo 19 Enterprise database. The Odoo 20 section is read from the public development branch and marked as unreleased. Spotted an error? Tell us and we will correct the page.