Chosen select widgets

The widget the Chosen module puts over a select, in every shape it takes: single and multiple, placeholder and deselect, grouped and flat, searchable and not, capped, disabled, in error, and opted out for comparison. A Chosen dropdown closes on blur, so it is gone the moment you look at anything else -- the inspector included. The toolbar at the top of the page pins every widget open and keeps it interactive, and the widgets in "The drop, held open" are already open when the page loads, each in a result state that is otherwise a moving target: highlighted, searched, and empty. Nothing is saved and every option list is made up.

Hold the widgets still

A Chosen dropdown closes on blur, so it is gone the moment you look at anything else. Pin them open and they stay open -- and stay usable, so you can still type in the search and walk the results with the arrow keys.

Stops every widget on the page closing itself, whatever it is you click next.
A drop is positioned over what follows it. This pushes the widgets apart so that several can be open at once without overlapping.
Adds the disabled attribute to each select, which Chosen answers by putting chosen-disabled on its container.
Puts the error class on each select and on the container Chosen built for it, which is what a failed validation looks like.
Flips the direction of the page and puts chosen-rtl on each container, the way a RTL language does.

Single value

One `.chosen-single` anchor showing the selected option, and the drop that opens under it. The variations are the ones that change the markup rather than only the contents: whether there is a search field at all, whether the selected option can be given back, and whether the results are a flat list or a grouped one.

Plain

The default. Eight options, a search field, and the first option selected because nothing said otherwise.

Placeholder, nothing selected

An empty first option makes the placeholder show. It is a span inside the anchor, not a real placeholder attribute, so it takes its colour from whatever the theme says rather than from ::placeholder.

Deselectable

allow_single_deselect adds a close button inside the anchor, which needs the first option to have an empty label as well as an empty value. Two controls in one line: the anchor opens the drop, the cross inside it clears the value without opening anything.

Grouped options

An optgroup becomes a `.group-result` list item, and the options under it get `.group-option`. The group heading is a sibling of the results rather than a parent of them, so the indent is the only thing saying which results belong to it.

Options that cannot be picked

A disabled option becomes a `.disabled-result`, which is in the list and not selectable. Core has no way to say this from a render array, so the three of them here are disabled by the script of this page before Chosen is told to read the select again.

Long list, long labels

Forty options in a drop with a fixed maximum height, so the results scroll. The labels are longer than the control is wide, which is the case that decides whether the theme truncates them, wraps them, or lets the drop grow past the control.

Create an option

With create_option on, a search that matches nothing offers to add what was typed instead of saying there is nothing. The offer is an active result like any other, with a class of its own -- `.create-option` -- so it can be told apart from the list it sits above.

Multiple values

A `.chosen-choices` list, one `.search-choice` pill per value and a search field as the last item of the same list. The control grows downwards as pills are added, which is the part that catches a theme out: its height is not a line height, and whatever sits beside it has to survive the control being three rows tall.

Nothing chosen

At its shortest the control is a single row holding only the search field, whose placeholder is the whole of what is showing.

A few values

Three pills and the search field after them. Each pill is a list item holding a span and a close button, so the close button has to be vertically centred against text it is not inside.

Enough values to wrap

Twelve pills, several of them longer than the control is wide. This is where a theme finds out whether its pills wrap, truncate or push the control wider than its column.

Capped at three

A field with a cardinality passes it to Chosen as max_selected_options. Once the cap is reached the drop refuses to open and fires chosen:maxselected instead, so the only thing that changes on the page is that nothing happens -- worth knowing before chasing it as a bug.

Grouped, with values already in

The chosen values are removed from the results as they are picked, so a group can empty out and disappear from the drop while its heading stays in the markup only as long as something under it is left.

A value that cannot be removed

A pill built from a disabled option has no close button and gets `.search-choice-disabled`, which is how a value that is set for you rather than by you shows up. Same disabling by script as the single value list above.

States

What the control looks like when it is not simply sitting there waiting. The toolbar can put the whole page into most of these at once; the widgets here are in them from the start, so the two can be compared side by side.

Disabled

chosen-disabled on the container and the search field disabled under it. The original select is disabled too, so the value still posts as nothing.

Disabled, with values

The same on a multiple: the pills stay and their close buttons go, so the control reads as a list of values rather than as a control.

Failed validation

Chosen copies the classes of the select onto its container when inherit_select_classes is on, which the module always sets. So the error class core adds on a failed validation does reach the widget -- but only the container, and only at the moment the widget is built.

Required

The required marker is on the label of the form item, which is markup Chosen never touches. Worth checking all the same: the label is now pointing at a select nobody can see.

Disabled by #states

The checkbox disables the widget under it through the states system, which sets the attribute rather than rebuilding the form. Chosen watches for that and redraws itself, so this is the path a conditional field takes on a real form.

Opted out, for comparison

The same options with #chosen set to FALSE: chosen-disable goes on the select and the library is never attached, so this is the plain control the theme styles everywhere else. It is here to be looked at next to the ones above.

The drop, held open

Every widget in this section is open when the page loads and stays open: the two methods a Chosen instance closes itself through are replaced with ones that do nothing. Click into them, type in them, walk them with the arrow keys -- the only thing they will not do is disappear. Turn on "Reserve room" in the toolbar if the drops are landing on top of each other.

Open, nothing highlighted

The drop with the selected option carrying `.result-selected` and no row highlighted at all. Chosen highlights something the moment it opens, so this state does not survive a real click on the control -- it is here to be looked at beside the one below it.

Open, with a result highlighted

`.highlighted` is the row under the pointer or the one the arrow keys have reached, and it is a different thing from `.result-selected`, which is the row holding the current value. Here the fourth row is highlighted and the first is selected, so both can be seen at once.

Open, with a search term

A term in the search field filters the results and wraps the matching part of each label in an `em`. That em is inside the anchor of the result, so it inherits everything the theme said about the row and needs its own answer for the match.

Open, with nothing matching

The one result state that is not a result: a single `.no-results` item carrying the text from the module settings, with the term the visitor typed inside a span. It is the only row in the drop, so a theme that styles rows through the anchor inside them will miss it -- there is no anchor.

Open, grouped

Group headings and their options in the drop at once, so the indent, the weight and the spacing above each group can be judged against each other rather than one at a time.

Open, scrolled

Forty results against the maximum height of the drop. The list scrolls inside the drop rather than the drop growing, so the theme owns both the height it stops at and the scrollbar that then appears inside a rounded, bordered box.

Open, on a multiple

The drop of a multiple hangs off a control that is several rows tall, and it has to keep hanging off the bottom of it as pills are added. Add one and watch what moves.

Open, upwards

Near the foot of the window Chosen puts `.chosen-dropup` on the container and the drop opens above the control instead. The border radius turns over with it -- rounded at the top, square where it meets the control -- so it is a second set of rules, not the same one mirrored. This one is forced into that state rather than waiting for the scroll position to produce it.

In context

The widget is only as good as the room it is given. These are the four places a select turns up on a back office page, and each of them takes the width away from it in a different way.

Inside a details element

Chosen measures the control to set its own width, and a closed details element has no width to measure. Open the group and the widget inside it is the one to check: it was built while it was hidden.

In a narrow column

Held to fourteen characters of width with labels far longer than that, which is the shape of a select in the last column of a table.

In a row of filters

The shape of an exposed filter: two widgets and a button on one line, each in its own form item. The widget is inline-block and the button is not, so the baseline they share is the thing to look at.

In a table

A widget in a cell has whatever width the column ended up with, and its drop opens over the row beneath. Two rows, so the overlap is visible; the labels are hidden the way a table of widgets hides them.

Class Room Awarding bodies
Monday evening
Thursday morning