Skip to main content
iVentureTeam

many2many_tags_skills

Skills rendered as tags that also carry whether the level is the default one. The extra data is injected rather than requested, so the view stays simple.

Siddharth JambukiyaSiddharth JambukiyaOdoo Techno-Functional Consultant
August 27, 2026Updated August 29, 20264 min read
Technical namemany2many_tags_skills
Field typesmany2many
Viewsform
Modulehr_skills, employee skills
Used in coreSkills fields in hr_skills
VersionsOdoo 20.0, Odoo 19.0, Odoo 18.0
No-code setupNo. It is set in view XML and depends on module-specific data
Alternativesmany2many_tags, many2one_tags_skills, skills_one2many, boolean_toggle_load

What the skills tags does

A skill on an employee is a pair: the skill itself and the level. Rendered as a plain tag, only the first survives, and a list of skills without levels is close to useless for anything except knowing that the skill exists.

This widget carries the extra information through. It swaps in a tag list component that can render more than a name, and supplies each tag with a flag saying whether the level attached is the default one for that skill.

The data for that flag is not something the view has to think about. The descriptor adds the field to what is loaded for each tag, so a view naming the widget gets it automatically.

What this means for your team

Skills data is only as useful as its precision. A search for people with a given skill is a different query from a search for people who are advanced at it, and the interface has to make the level visible or nobody maintains it.

The mechanism is worth reusing: injecting a related field in the descriptor rather than asking every view to load it keeps the widget self-contained and means a later view cannot forget the field the tag depends on.

Supported options in Odoo 19

The widget declares no options of its own. It spreads the tags widget's descriptor and extends the related fields it loads, which is the entry below. Read from many2many_tags_skills.js, Odoo 19.0.

OptionTypeWhat it does
default_levelinjected related fieldAppended by the descriptor to the fields loaded for each tag, and passed to the tag as a flag. The view does not have to declare it.(since Odoo 18.0)
no_quick_createbooleanInherited from the tags widget. Removes creation from the typed text.(default: false)
no_createbooleanInherited. Removes both creation paths from the dropdown.(default: false)
color_fieldfieldInherited from the tags widget. Names an integer field used to color the tags.

The extra field is injected, not requested. The descriptor appends it to whatever the base widget already loads for each tag, so the view needs no extra declaration and cannot omit it by accident.

Working examples

The usual usage

<field name="skill_ids"
       widget="many2many_tags_skills"/>

No options and no extra fields; the default level flag arrives with the tag data.

Restricting creation

<field name="skill_ids"
       widget="many2many_tags_skills"
       options="{'no_quick_create': True}"/>

Inherited from the tags widget, and useful where skills should come from a maintained list.

The plain tags widget

<field name="skill_ids" widget="many2many_tags"/>

Names only, with no level information on the tag.

Asking for the data it needs

Two changes, both small. The components map is extended so the tag list is the skills-specific one, and the method building each tag's properties adds the default level flag read from the tag's own record.

The descriptor then extends the related fields function so that flag is loaded. Doing it in the descriptor rather than in the view is the detail worth copying: a widget that needs data to render should ask for it itself, not depend on every view remembering.

What the flag actually looks like on screen belongs to the tag list component, not to this file, which is why the widget can stay this short.

On the development branch the tag components across Odoo are reworked, so this widget changes with them. The concept, a tag carrying its level context, is what to expect to survive rather than the exact structure.

Version compatibility

VersionStatusNotes
Odoo 20.0Partial / changedNot released. Reworked alongside the tag components; the concept is unchanged.
Odoo 19.0VerifiedVerified against the shipped source. Identical to Odoo 18.
Odoo 18.0VerifiedFirst version.
Odoo 17.0Not availableWidget does not exist.
Odoo 16.0Not availableWidget does not exist.

Upgrade note. The widget arrived in Odoo 18 and the Odoo 18 and Odoo 19 files are identical, so views carry over. The development branch reworks the tag components underneath it, which matters to customizations of the tag rendering rather than to views.

What is changing in Odoo 20

Odoo 20 is expected at Odoo Experience in Brussels, 24 to 26 September 2026. The development branch is unstable and this may still change; we re-verify this page after the release.

Reworked with the tag components. The development branch changes this widget as part of the wider rework of how tags are built. The injected field and the concept of a level-aware tag are unchanged; the structure around them is not.

Common problems and fixes

SymptomCause and fix
Tags show no level contextThe tag list component was overridden, or the injected field is not reaching the tag. Keep the widget's own components map when customizing.
The default level flag is always falseNo level is marked as default on those skills. Set the default level on the skill type.
Skills can be created from the inputCreation is allowed by default on the tags widget. Pass no_quick_create or no_create in the options.
Tags have no colorNo color field is configured. Set the color_field option to the integer field on the skill.
Options are ignoredThe widget declares none of its own; the inherited tag options work normally. Use the tags widget's options as usual.
Missing widget errorThe skills module is not installed in that database. Install it, or use the plain tags widget.

Skills tags vs the alternatives

WidgetBest forKey difference
many2many_tags_skillsSkills shown as tags that also convey their level contextInjects the default level field itself and renders it through a dedicated tag list
many2many_tagsAny relation shown as tagsNames only, with no injected context
many2one_tags_skillsEditable skill linesA child list rendered as tags, with its own dialog
skills_one2manySkills as a full listA table rather than tags
boolean_toggle_loadMarking a level as the defaultA toggle on the level rather than a display of it

The plain tags widget is right wherever the extra context is unnecessary. Within the Skills module, the one-to-many variant renders editable skill lines rather than tags, and is the better choice where levels are set rather than just displayed.

Frequently asked questions

Where does the level information come from?+
A field the descriptor injects into what is loaded for each tag, then passed to the tag as a flag. The view does not declare it.
Why inject rather than ask the view to load it?+
So the widget is self-contained. A view cannot forget a field the widget requires if the widget asks for it itself.
Does it support the tags widget's options?+
Yes, all of them. It spreads that descriptor and only adds the injected field and the tag property.
What renders the flag?+
The skills-specific tag list component the widget substitutes, not the widget itself.
Which versions have it?+
Odoo 18 onwards. The development branch reworks it alongside the wider tag component changes.

Knowing who can actually do the work

Skills, levels and certifications only help resourcing if they are precise enough to search on. We set up Odoo HR skills and the planning that uses them, on versions 16 through 19.

Book a free consultation

How this page was produced

The tag list substitution, the added tag property and the extended related fields function were read from many2many_tags_skills.js on the Odoo 19.0 branch, with the inherited option set read from the tags field in web. Version coverage comes from the absence of the file on 16.0 and 17.0, a comparison with 18.0, and a comparison against the public development branch. Spotted an error? Tell us and we will correct the page.