Skip to main content
iVentureTeam

hr_applicant_state_selection

The colored state bullet on an Odoo recruitment applicant is not the standard state_selection widget. hr_applicant_state_selection exists because hr.applicant carries a fourth kanban state, Waiting, that needed its own color.

Siddharth JambukiyaSiddharth JambukiyaOdoo Techno-Functional Consultant
August 26, 2026Updated August 26, 20265 min read
Technical namehr_applicant_state_selection
Field typesselection
Viewsform, kanban
Modulehr_recruitment
Used in core2 occurrences across 1 module: the hr.applicant form and kanban views in hr_recruitment
VersionsOdoo 20.0, Odoo 19.0
No-code setupNo. Applied in XML; Studio does not list it
Alternativesstate_selection, project_task_state_selection, event_state_selection

What the Applicant state widget does

On an applicant card or form in Odoo Recruitment, the small colored bullet next to the title is this widget. It renders kanban_state on hr.applicant and opens a dropdown with the four states the model defines: In Progress, Ready for Next Stage, Waiting and Blocked.

The widget is a 25-line subclass of the generic state_selection widget. Its one change is the color map it installs in setup(): blocked red, done green, and waiting orange. The base widget only knows red and green, because the standard kanban_state selection on other models has three values. Recruitment redeclares the field with a fourth value, waiting, and this widget exists to give that value a color.

Everything else is inherited: the dropdown, the label substitution from stage legends, the autosave behavior, and the command palette entries in form views.

What this means for your team

The four states are a lightweight triage layer that lives across stage columns. A recruiter can keep an applicant in the Interview stage while flagging whether the file is moving (In Progress), stalled on the candidate (Waiting), stalled internally (Blocked), or ready to advance (Ready for Next Stage).

The orange Waiting state is the one recruitment teams actually use most, and it is the reason this widget exists: waiting on candidate feedback, references, or a signed offer is the default condition of a hiring pipeline, and it is different from Blocked, which signals your side owes an action.

Because the labels come from the stage's legend fields, each recruitment stage can rename what the states mean. On the Contract Proposal stage, Ready for Next Stage can read as Offer accepted; the bullet colors stay consistent while the words adapt to the stage, which is how the standard Odoo data set uses it.

Supported options in Odoo 19

The widget declares no options of its own. It spreads the full stateSelectionField descriptor from web, so the two generic options below pass straight through, verified in the Odoo 19.0 source of both files.

OptionTypeWhat it does
autosavebooleanInherited from state_selection. When true, which is the default even if the option is omitted, picking a state saves the whole record immediately, including any other pending edits. Pass {'autosave': False} to keep the change pending until the form is saved.(default: true)(since Odoo 19.0)
hide_labelbooleanInherited from state_selection. The inherited extractProps hides the label whenever this option is absent, so the widget shows a bare bullet by default; write {'hide_label': False} to print the state name, or its stage legend, next to it.(default: true (label hidden))(since Odoo 19.0)

The label is hidden by default. The inherited extractProps only shows the state label when you explicitly pass {'hide_label': False}, which is how the widget renders as a compact bullet in the applicant kanban footer.

Working examples

How core applies it on the applicant form

<field name="legend_normal" invisible="1"/>
<field name="legend_blocked" invisible="1"/>
<field name="legend_waiting" invisible="1"/>
<field name="legend_done" invisible="1"
<field name="kanban_state" widget="hr_applicant_state_selection" class="o_field_state_selection"/>

The invisible legend fields are not decoration. The inherited dropdown builds its labels from record.data['legend_' + state], so the four related fields must be loaded in the view or the dropdown falls back to the raw selection labels.

Showing the label next to the bullet

<field name="kanban_state" widget="hr_applicant_state_selection"
       options="{'hide_label': False}"/>

Turning off the immediate save

<field name="kanban_state" widget="hr_applicant_state_selection"
       options="{'autosave': False}"/>

By default a state change saves the whole record immediately, including any other unsaved edits on the form.

Hotkeys, stage dates, and what the subclass inherits

The interesting engineering is in what the subclass inherits, and one place where the inheritance shows a seam.

The fourth state outruns the hotkeys. The base widget registers one command palette entry per selection value in form views, assigning hotkeys from a hardcoded three-letter list: Alt+D, Alt+F, Alt+G. On a three-value model that covers everything. On hr.applicant's four-value selection, the entries register in selection order, so In Progress, Ready for Next Stage and Waiting get the three hotkeys and the fourth entry, Blocked, registers with no hotkey at all. It is still reachable by typing in the command palette, just not by key combination. We verified this against the base setup() in Odoo 19.0.

The state also drives dates. On the server side, any write to kanban_state stamps date_last_stage_update, and moving the applicant to a new stage resets the state to normal. So the bullet quietly participates in the recruitment KPIs that measure time in stage.

Server-set values, not widget magic. The widget never computes anything; it displays and writes the selection. Automated flows such as interview forms or refuse reasons set waiting or blocked from Python, and the widget simply shows the result.

Version compatibility

VersionStatusNotes
Odoo 20.0In developmentNot released. The widget file is byte-identical on the development branch; see below.
Odoo 19.0VerifiedWidget introduced. Verified against the shipped source.
Odoo 18.0Not availableWidget does not exist; the applicant form used the generic state_selection.
Odoo 17.0Not availableWidget does not exist.
Odoo 16.0Not availableWidget does not exist.

Upgrade note. Before Odoo 19 the applicant form used the generic state_selection widget, which renders the waiting value with the default gray bullet. Custom views migrated from 17 or 18 keep working if they still name the old widget; they just lose the orange color for Waiting.

What is changing in Odoo 20

Odoo 20 is expected at Odoo Experience in Brussels, 24 to 26 September 2026, and until release the development branch can still change.

As of this writing, hr_applicant_state_selection.js is byte-identical between Odoo 19.0 and the development branch: same color map, same registration, same inheritance. Note that the generic parent widget is losing its autosave option upstream in the same cycle, which would change the immediate-save behavior this subclass inherits. We re-verify both files against the shipped release.

Common problems and fixes

SymptomCause and fix
The dropdown shows raw labels like In Progress instead of the stage's custom wordingThe legend_* related fields are not loaded in the view; the widget reads them from record data. Add legend_normal, legend_blocked, legend_waiting and legend_done as invisible fields, as the core form does.
Waiting shows a gray bullet instead of orangeThe view uses the generic state_selection widget, which has no color for the waiting value. Switch the field to widget="hr_applicant_state_selection".
Changing the state saves the form before the user is done editingThe inherited autosave option defaults to true and saves the entire record on selection. Pass options="{'autosave': False}" if the state change should stay pending.
Alt+D, Alt+F or Alt+G triggers the wrong stateHotkeys are assigned by selection order, and hr.applicant has four values for three hotkeys; Blocked gets none. Use the command palette entries by name; the hotkey mapping is hardcoded in the base widget.
The state resets to In Progress after moving the applicant to another stageServer behavior on hr.applicant: writing a new stage_id resets kanban_state to normal unless the write sets it explicitly. This is intentional; re-set the state after the stage move if your flow needs it.

Applicant state widget vs the alternatives

WidgetBest forKey difference
hr_applicant_state_selectionThe four-value applicant state on hr.applicant in recruitment viewsAdds an orange color for the recruitment-specific waiting state on top of the generic widget
state_selectionThe standard three-value kanban_state on any other modelSame dropdown and options but only red and green in its color map
project_task_state_selectionTask states in project, including approval and canceled valuesDifferent state vocabulary with its own icons and a toggle click mode
event_state_selectionEvent kanban states including a Cancelled valueHardcodes a four-state order with icon glyphs and drops the base hotkey commands

Use this widget only on hr.applicant, where the four-value selection and the legend fields exist. On any other model the generic state_selection is the right choice, and models with their own state vocabulary usually ship their own subclass, as project and event do.

Frequently asked questions

What is the hr_applicant_state_selection widget in Odoo?+
It is the recruitment-specific version of the state bullet, added in Odoo 19. It renders the kanban_state field on hr.applicant and colors the fourth, recruitment-only value waiting in orange, alongside the standard red for blocked and green for done.
Why does hr.applicant have four kanban states instead of three?+
The model redeclares the selection as In Progress, Ready for Next Stage, Waiting and Blocked. Waiting expresses that the ball is in the candidate's court, which is different from Blocked, where your team owes an action.
Can I rename the state labels per recruitment stage?+
Yes. Each hr.recruitment.stage has legend fields (legend_normal, legend_blocked, legend_waiting, legend_done) and the widget substitutes them as dropdown labels, as long as those related fields are loaded in the view.
Does changing the applicant state save the record immediately?+
By default yes; the inherited autosave option is true even when omitted, and the save includes any other pending edits on the form. Pass options="{'autosave': False}" to defer it.
Can I use hr_applicant_state_selection on my own model?+
Technically yes if your selection uses the same value keys, since the widget only installs a color map. But the legend substitution expects legend_* fields, and values other than blocked, done and waiting fall back to the gray bullet. For other models the generic state_selection is usually the better base.

Recruitment pipeline that mirrors how you actually hire?

We tailor Odoo Recruitment end to end: stage legends that speak your language, applicant states wired to automated interview and offer flows, and custom kanban indicators your recruiters read at a glance, on Odoo 16 through 19.

Talk to an Odoo HR expert

How this page was produced

This page was verified by reading hr_applicant_state_selection.js in the Odoo 19.0 hr_recruitment module together with the base state_selection_field.js in web, the kanban_state field declaration in hr_applicant.py, and both core view usages in hr_applicant_views.xml. The Odoo 20 section comes from a diff against the public development branch and is marked unreleased. Spotted something off? Tell us and we will fix it.