Skip to main content
iVentureTeam

handle

The drag dots on the left of Odoo list rows are the handle widget. It has no options at all; everything that matters happens in the sequence field underneath it.

August 11, 2026Updated August 11, 20266 min read
Odoo 19 sales order lines with the handle widget's drag dots on the left of each row, one row mid-drag.
Technical namehandle
Field typesinteger
Viewslist (including one2many lists)
Moduleweb, present in every Odoo database
Used in core155 occurrences across 58 modules, including account, event, website_slides, product, project, mrp
VersionsOdoo 20.0, Odoo 19.0, Odoo 18.0, Odoo 17.0, Odoo 16.0
No-code setupPartly: Studio can add a sequence field, but the widget is set in XML
Alternativespriority, integer, statusbar

What the handle widget does

Every list in Odoo that users can rearrange by hand, sales order lines, project stages, product attribute values, has a column of drag dots on the left. That column is the handle widget on an integer field, almost always one named sequence.

The mechanics are simpler than they look. The widget renders nothing but the dots; the source component is a template with no logic of its own. When a user drops a row in a new position, the list view rewrites the integer values of the moved row and every row it displaced, then saves. The "order" is never stored as an order; it is just integers the list sorts by.

That is also why the source declares isEmpty: () => false and a fixed listViewWidth of 20 pixels: the column always renders, always tiny, whatever the value holds.

What this means for your team

Manual ordering is one of those features nobody lists in requirements and everybody expects. Quotation lines must print in the order the salesperson arranged them. Manufacturing steps must appear in execution order. Pipeline stages must match how the team actually works, not alphabetical accident.

The handle widget is the difference between "drag it where you want it" and a support ticket asking why the quotation prints in the wrong order. On implementations we add a sequence field plus handle to almost every custom line model by default, because retrofitting user-controlled order after go-live means touching data, views and reports at once.

One process note: the order is data, not preference. When one user reorders lines, everyone sees the new order, including reports and the customer-facing PDF. Teams occasionally expect per-user ordering; that is a different feature entirely.

Setting it up in Odoo Studio (no code)

Studio can create the underlying field, but applying the handle widget itself is a view-XML step.

  1. In Studio, add an Integer field to the line model and name it sequence (turn on developer mode first so you can set the technical name).

  2. Set its default value so new rows land at the end, for example 10.

  3. Exit Studio; the widget assignment (widget="handle") and the list ordering are added in the view XML as shown below.

What Studio cannot do here

Studio's widget selector does not offer Handle on integer fields, and Studio cannot set a list view's default_order. Both are one-line XML changes, which makes this a very small developer task rather than a Studio one. If drag ordering is on your wishlist, it usually rides along free with any other view work you commission.

Supported options in Odoo 19

Verified against handle_field.js in the Odoo 19.0 web module: the descriptor declares no supportedOptions at all. There is genuinely nothing to configure on the widget; the rows below document the field-level requirements that make it work instead.

OptionTypeWhat it does
(none)n/aThe widget declares no supportedOptions in the source. Requirements live at field and view level: an integer field, widget="handle" on it, and the list sorted by that same field.

The number one failure mode is a sorting mismatch. The widget writes the integer, but the LIST decides the display order. If the list is sorted by anything other than the handle's field, by a date column the user clicked, or a model _order that ignores sequence, dragging saves values you never see applied. Keep default_order="sequence" on the list and put sequence first in the model's _order.

Working examples

The standard pattern

<list default_order="sequence">
    <field name="sequence" widget="handle"/>
    <field name="name"/>
</list>

Two requirements in two lines: the handle on the integer field, and the list ordered by that same field.

The model side

class QuoteLine(models.Model):
    _name = "my.quote.line"
    _order = "sequence, id"

    sequence = fields.Integer(default=10)
    name = fields.Char(required=True)

The id tiebreaker keeps rows with equal sequence values stable. The default of 10 means new rows append rather than jumping to the top.

Inside a one2many on a form

<field name="line_ids">
    <list editable="bottom" default_order="sequence">
        <field name="sequence" widget="handle"/>
        <field name="product_id"/>
    </list>
</field>

The same pattern works in embedded lists, which is where users meet it most: order lines, BoM components, checklist items.

What a drag actually writes

Understanding what dragging actually writes saves debugging time later.

Dropping a row renumbers its neighbors. Odoo does not shift everything by one; it rewrites the sequence integers of the rows between the old and new positions. Expect several records in the write log from a single drag, and expect write-date and audit trails to reflect that.

Grouped lists constrain dragging. With grouping active you can reorder inside a group, and dragging between groups is either blocked or means something else (changing the grouped field), depending on the view. If users report "dragging stopped working", the first question is whether they grouped the list.

Automations fire. A drag is a write on the sequence field of several records. Automated actions or write overrides watching those models will trigger once per touched row, which matters if your automation is heavy or logs noisily.

Version compatibility

VersionStatusNotes
Odoo 20.0In developmentNot released. The development branch shows no behavior changes; see below.
Odoo 19.0VerifiedVerified against the shipped source and tested on a clean database.
Odoo 18.0VerifiedSame behavior. No XML changes needed.
Odoo 17.0VerifiedSame behavior. No XML changes needed.
Odoo 16.0VerifiedSame behavior. No XML changes needed.

Upgrade note. The widget is one of the most stable in the codebase: no options in any supported version, so view XML from Odoo 16 carries to 19 untouched. Anything that broke after a migration is in the list ordering or a customized list view, not in the widget.

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.

Nothing changes for this widget. The development version of handle_field.js is identical in behavior: same absence of options, same integer-only support, same 20px column. Only the internal component syntax moves to the new Owl props system, which affects JavaScript patches and nothing in XML. We re-verify this page once Odoo 20 ships.

Common problems and fixes

SymptomCause and fix
Dragging a row snaps it back to where it wasThe list is sorted by another column or the model's _order ignores the sequence field. Set default_order="sequence" on the list and put sequence first in _order.
Drag dots do not appearThe widget sits on a non-integer field, or the user lacks write access to the records. Check the field type is integer and the user can write; the handle hides in readonly contexts.
Dragging between groups does nothingGrouped lists restrict reordering to within a group by design. Remove the grouping to reorder freely, or drag within the group.
New rows appear at the top instead of the endThe sequence field's default is 0 while existing rows carry higher values. Give the field a default like 10, or compute the next value in create().
Report or PDF ignores the dragged orderThe report query has its own sort and does not order by sequence. Order the report's recordset by sequence explicitly.

Handle widget vs the alternatives

WidgetBest forKey difference
handleLists users arrange by hand: order lines, stages, stepsWrites integers into a sequence field; the list's sort order does the rest
priorityRanking a few records by importanceStars set a level per record; they do not define a total order
integerTyping exact sequence numbers directlyManual number entry, no dragging; useful for bulk renumbering
statusbarPosition in a workflow rather than in a listMoves a record through stages; unrelated to row order

The practical test: if users should arrange rows by feel, give them the handle. If the order follows a rule, a date, a priority, a stage, sort by that field instead and skip manual ordering entirely; mixing both confuses everyone.

Frequently asked questions

How do I let users drag and drop rows in an Odoo list?+
Add an integer field (conventionally sequence) to the model, put <field name="sequence" widget="handle"/> as the first column, and sort the list by it with default_order="sequence". Both pieces are required.
Why does dragging rows not change the order?+
Almost always because the list is sorted by something else. The drag wrote the integers, but the display order follows the active sort. Reset the list's sort to the sequence column and the saved order appears.
Does the handle widget have any options?+
No. Verified in the Odoo 19 source: the descriptor declares no supportedOptions. All configuration lives on the field (type, default) and the view (order).
Can I add drag-and-drop ordering from Odoo Studio?+
Halfway. Studio can create the integer field, but assigning widget="handle" and setting the list's default_order are XML edits. It is a two-line change for a developer.
What does Odoo write when I drag a row?+
New integer values on the moved row and each row it displaced, saved immediately. That means several records get a write from one drag, which shows in audit logs and can trigger automations watching those models.
Does the handle work in kanban views?+
Kanban cards are draggable, but that is the kanban view's own record-and-group handling, not this widget. The handle widget itself is a list-view control on an integer column.

Lists that never sit in the right order?

Drag-and-drop ordering, sensible defaults for new rows, and reports that respect the arranged order are small view-and-model changes we bundle into any Odoo customization work, on Odoo 16 through 19.

Book a free consultation

How this page was produced

The behavior was read from the Odoo 19.0 web module source (handle_field.js), which is short enough to quote: no options, integer-only, fixed 20px list column. The renumbering and grouped-list behavior was confirmed on a clean Odoo 19 database, where the screenshot was captured. The Odoo 20 statement comes from the same file on the public development branch, where it is unchanged. Spotted an error? Tell us and we will correct the page.