# Adapter feature parity

Chosen's jQuery and Prototype adapters define the current behavior in [Options and API](options.html). The vanilla JavaScript and React editions are experimental. **Neither is a drop-in replacement yet.** This inventory is based on the source and public APIs on 2026-09-28; keep it current when behavior changes.

The goal is equivalent behavior and defaults in all editions, expressed through each platform's natural API. React props can use camelCase and callbacks; vanilla can use native DOM events. An adapter-specific mechanism is acceptable only when users can achieve the same result. Avoid changing an existing default silently; document a migration or release boundary when aligning one.

All four editions can initialize from allowed external scripts under a strict
Content Security Policy. The classic multiple-select search input no longer
emits an inline width attribute; its default width comes from `chosen.css`.
See the [CSP integration guide](csp.md).

The opt-in `chosen-jjj/remote` source controller manages bounded async pages,
stale responses, and selected-value retention for the classic and Vanilla
editions. React exports a matching `useRemoteOptions` hook. Each edition still
reports queries through its existing search event or callback. This is not DOM
virtualization for a pre-populated select. See [Remote search with Chosen](remote-search.md)
and the working example on all four demo pages.

`Yes` means the option has equivalent configurable behavior. `Partial` means some behavior exists but the setting, default, or an important edge case differs. `No` means the public adapter does not implement it. The jQuery and Prototype columns are omitted because the classic reference is the baseline, not because their individual tests can be skipped.

| Classic option | Vanilla | React | Gap or equivalent API |
| --- | --- | --- | --- |
| `allow_single_deselect` | Yes | Yes | React prop: `allowSingleDeselect`, default `false`. |
| `allow_select_all` | Yes | Yes | Filtered bulk selection with Ctrl/Command+A on an empty search. React prop: `allowSelectAll`. |
| `allow_deselect_all` | Yes | Yes | Clear enabled selections with Ctrl/Command+Shift+A on an empty search. React prop: `allowDeselectAll`. |
| `deselect_selected_results` | Yes | Yes | React prop: `deselectSelectedResults`; defaults to `false`. Both demos opt in to selected-row removal. |
| `shift_select_range` | Yes | Yes | Visible Shift-click range selection for multiple selects, off by default. React prop: `shiftSelectRange`. |
| `select_all_text` | Yes | Yes | Bulk action label; React prop: `selectAllText`. |
| `deselect_all_text` | Yes | Yes | Bulk action label; React prop: `deselectAllText`. |
| `disable_search` | Yes | Yes | Single-select search is hidden; typing prefixes navigates results. React prop: `disableSearch`. |
| `disable_search_threshold` | Yes | Yes | Hide single-select search at or below the option count. React prop: `disableSearchThreshold`. |
| `enable_split_word_search` | Yes | Yes | React prop: `enableSplitWordSearch`. |
| `inherit_select_classes` | Yes | Yes | Vanilla opts into copying source classes; React uses `className` directly on its generated host. |
| `inherit_option_classes` | Yes | Yes | Option and group classes reach result rows; opt in to copying option classes to selected chips. React uses `className` on option data and `inheritOptionClasses`. |
| `inherit_optgroup_classes` | Yes | Yes | Opt in to copying a parent optgroup's classes to selected multiple-choice chips. React uses `inheritOptgroupClasses`. |
| `max_selected_options` | Yes | Yes | Both enforce the limit. |
| `max_items_shown` | Yes | Yes | Positive integer limit for visible chips; React prop: `maxItemsShown`. |
| `paste_multiple_values` | Yes | Yes | Opt-in token paste selects unique enabled existing options and preserves unmatched text; React prop: `pasteMultipleValues`. |
| `more_items_text` | Yes | Yes | Hidden-choice count callback; React prop: `moreItemsText`. |
| `show_fewer_items_text` | Yes | Yes | Expanded summary button copy; React prop: `showFewerItemsText`. |
| `no_results_text` | Yes | Yes | React prop: `noResultsText`; custom text is used literally before the query. Vanilla also reads source `data-no_results_text`. |
| `no_results_template` | Yes | Yes | React prop: `noResultsTemplate`; optional plain-text `{search}` marker places the escaped query within localized copy. |
| `create_option` | Yes | Yes | Vanilla appends to the source select or calls a supplied function; React `createOption` adds a local option and calls optional `onCreateOption`. Controlled parents must update `value`. |
| `create_option_text` | Yes | Yes | New-option action label; React prop: `createOptionText`. Vanilla also reads `data-create_option_text`. |
| `persistent_create_option` | Yes | Yes | Keep creation available when results match but no exact option exists; React prop: `persistentCreateOption`. |
| `skip_no_results` | Yes | Yes | Hide no-results copy during creation; React prop: `skipNoResults`. |
| `results_count_text` | Yes | Yes | React prop: `resultsCountText`; both accept `(count) => text` for the live result count. |
| `placeholder_text_multiple` | Yes | Yes | React prop: `placeholderTextMultiple`. |
| `placeholder_text_multiple_selected` | Yes | Yes | Optional hint after a multiple select has at least one choice. React prop: `placeholderTextMultipleSelected`. |
| `placeholder_text` | Yes | Yes | React prop: `placeholder`; type-specific props take precedence. |
| `placeholder_text_single` | Yes | Yes | React prop: `placeholderTextSingle`. |
| `search_contains` | Yes | Yes | React now defaults to `false`, matching classic. |
| `search_word_boundary` | Yes | Yes | Opt-in regular-expression source for word starts; React prop: `searchWordBoundary`. |
| `highlight_prefix_matches` | Yes | Yes | React prop: `highlightPrefixMatches`; result order is unchanged. |
| `search_matcher` | Yes | Yes | React prop: `searchMatcher`; both receive normalized items. |
| `search_input_type` | Yes | Yes | Both default to `search` and accept `text`; React prop: `searchInputType`. |
| `min_search_length` | Yes | Yes | React prop: `minSearchLength`. |
| `max_search_length` | Yes | Yes | React prop: `maxSearchLength`; both default to 1000. |
| `normalize_search_text` | Yes | Yes | React prop: `normalizeSearchText`. |
| `split_search_terms` | Yes | Yes | Order-independent multi-term matching. |
| `search_delay` | Yes | Yes | Debounced results, flushed before navigation or selection keys; React prop: `searchDelay`. |
| `search_in_values` | Yes | Yes | React prop: `searchInValues`. |
| `group_search` | Yes | Yes | Include group labels in matching. |
| `parser_config` | Yes | Yes | Vanilla supports `{copy_data_attributes: true}`; React uses option `dataAttributes` plus `copyOptionDataAttributes`. |
| `backspace_deletes_choices` | Yes | Yes | React prop: `backspaceDeletesChoices`; defaults to `true`. |
| `single_backstroke_delete` | Yes | Yes | React prop: `singleBackstrokeDelete`; set `false` for first-press chip focus and second-press removal. |
| `multiselect_allow_tab_to_select` | Yes | Yes | React prop: `multiselectAllowTabToSelect`; defaults to `false`. Tab continues to the next focus target. |
| `open_on_label_click` | Yes | Yes | React prop: `openOnLabelClick`; labels focus singles and open multiples by default, with either behavior configurable. |
| `width` | Yes | Yes | Vanilla measures its source select initially and accepts `width` or `false`; React accepts `width` or `style`, since it has no source select to measure. |
| `dropdown_width` | Yes | Yes | Independent result width with a floating border; React prop: `dropdownWidth`. |
| `recalculate_width_on_update` | Yes | Yes | Vanilla remeasures its source select on `update()` when enabled. React has no source select to remeasure; change its `width` or `style` prop when layout changes. |
| `dropdown_position` | Yes | Yes | Fixed dropdown tracks scroll and resize; React prop: `dropdownPosition`. |
| `mobile_fullscreen` | Yes | Yes | Opt-in full-screen picker on touch screens up to 600px wide; React prop: `mobileFullscreen`. The native select still owns form values. |
| `display_disabled_options` | Yes | Yes | Configurable visibility. |
| `display_selected_options` | Yes | Yes | Configurable visibility. |
| `display_selected_value` | Yes | Yes | Value in the closed control; label remains in results. React prop: `displaySelectedValue`. |
| `include_group_label_in_selected` | Yes | Yes | Group name in selected text. React prop: `includeGroupLabelInSelected`. |
| `max_shown_results` | Yes | Yes | React prop: `maxShownResults`; group headings do not count. |
| `case_sensitive_search` | Yes | Yes | React prop: `caseSensitiveSearch`. |
| `hide_results_on_select` | Yes | Yes | React prop: `hideResultsOnSelect`; defaults to `true`. Both demos keep multiple results open with the opt-out. |
| `rtl` | Yes | Yes | Vanilla accepts `rtl: true` and follows source `dir` or the legacy `chosen-rtl` class; React has `dir`. |

## Source attributes and platform events

All four editions retain native form validation on their source select. When validation reports an invalid select, its native validation anchor aligns with the visible control; valid value changes and form reset restore the source select styles.

The vanilla edition reads strict scalar `data-*` initialization options, `data-placeholder`, native `placeholder`, option `data-search-text`, option `data-chosen-always-visible`, and `select-by-group`; it follows source `multiple`, `required`, `disabled`, `hidden`, selected values, reset, native change events, and applicable source ARIA attributes. Classic and Vanilla use an option's `label` attribute when its text is empty; React takes the equivalent `label` field in structured option data. Explicit JavaScript options override data attributes. React accepts structured option data rather than parsing a source select; `searchText`, `alwaysVisible`, `selectByGroup`, `hidden`, `disabled`, `multiple`, `required`, `readOnly`, selected values, and several ARIA props are available.

The vanilla adapter has native `chosen:*` lifecycle and search events on the source select, bubbling native `input`/`change`, and native `chosen:activate`, `chosen:open`, `chosen:close`, and `chosen:updated` commands. Its no-results events expose the rendered element and previous query when clearing. React has `onChange`, `onOpenChange`, `onReady`, popup callbacks, search callbacks, `onNoResults`, `onNoResultsClear`, and `onMaxSelected`. Both editions follow the classic single-select keyboard paths: Enter opens a closed list, Up at the first result closes when a choice is selected, and Backspace or Delete clears an eligible closed single selection. Neither API pretends jQuery `.trigger()` is a native event. Compare event payloads, cancelation, form reset, keyboard navigation, pointer and touch behavior, dynamic updates, label focus, search highlighting, and accessibility in tests before calling parity complete.

Single-select Tab is a current keyboard gap: classic jQuery and Prototype choose the highlighted result when the dropdown is open, then move focus onward. Vanilla and React close the dropdown and move focus without choosing. Their existing default is preserved until the selection contract and migration impact are reviewed across all editions.

## Completion gate

1. Implement the missing behavior in shared `core/` when it is independent of the renderer; keep platform-specific DOM and state code in each adapter.
2. Add adapter-specific options or props, types, docs, and demos with equivalent defaults. Where React cannot mutate a controlled options array, use an explicit callback and document the parent update.
3. Add focused cross-adapter behavior tests, browser and mobile checks for interaction changes, and representative visual checks.
4. Update this inventory to `Yes` or record a justified platform-specific equivalent for every row before treating either experimental edition as feature complete.
