Skip to content

Styling and Themes

John James Jacoby edited this page Oct 4, 2026 · 10 revisions

Styling and themes

Chosen ships usable default styles without imposing an application theme. Load application overrides after chosen.css.

The example pages support the operating-system color scheme and include a Light mode / Dark mode switch for testing.

The Vanilla and React editions each ship a standalone stylesheet. Their controls, chips, summary buttons, grouped results, and dropdowns use shared --chosen-* theme tokens, but their CSS classes are edition-specific. Both allow narrow layouts without a fixed 12rem control minimum. Try the Vanilla and React demos at phone width and in both color schemes before adding application overrides.

Light Dark
Chosen example page in light mode Chosen example page in dark mode

Theme variables

The compiled stylesheet exposes CSS custom properties, so applications can theme one control or a whole page without rebuilding Chosen. Set them on a wrapper or on .chosen-container:

.project-picker .chosen-container {
  --chosen-control-background: #fff;
  --chosen-dropdown-background: #fff;
  --chosen-text-color: #263238;
  --chosen-border-color: #8896a5;
  --chosen-active-color: #2563eb;
  --chosen-highlight-color: #2563eb;
  --chosen-focus-ring-color: #2563eb;
}

The Options page lists the available variables, including separate control, dropdown, search, selected choice, focus, icon, and density settings. Tailwind integrations can map those properties to theme tokens in a components layer; Chosen does not need Tailwind at runtime.

The classic light-theme highlight defaults to #3672d2 with white result text after PR #221. Check text contrast when replacing either highlight color in an application theme.

Tailwind and scoped themes

Load chosen.css and define the desired tokens in your Tailwind components layer. This works with Tailwind Preflight and the forms plugin; the compiled Chosen stylesheet still works on pages that do not use Tailwind.

@import "tailwindcss";
@plugin "@tailwindcss/forms";

@layer components {
  .chosen-container,
  .chosen-react {
    --chosen-control-background: var(--color-white);
    --chosen-text-color: var(--color-slate-900);
    --chosen-border-color: var(--color-slate-300);
    --chosen-border-radius: var(--radius-lg);
    --chosen-focus-ring-color: var(--color-indigo-500);
    --chosen-highlight-color: var(--color-indigo-600);
    --chosen-highlight-background: var(--color-indigo-600);
  }

  .dark .chosen-container,
  .dark .chosen-react {
    color-scheme: dark;
    --chosen-control-background: var(--color-slate-900);
    --chosen-dropdown-background: var(--color-slate-800);
    --chosen-text-color: var(--color-slate-100);
    --chosen-group-color: var(--color-slate-300);
    --chosen-muted-color: var(--color-slate-300);
    --chosen-active-color: var(--color-indigo-300);
    --chosen-disabled-opacity: 1;
  }
}

--chosen-highlight-color controls the classic dropdown highlight; --chosen-highlight-background controls React's. Set both for a shared palette. The full light/dark example and the token reference live on the Options page. A separate control can use its own wrapper or .chosen-container token overrides.

Tailwind dark theme with Select all and Deselect all

To show an invalid border, set aria-invalid="true" on the original select, or aria-invalid={true} on React Chosen. The opt-in border uses --chosen-invalid-border-color (#dc2626 by default); native :invalid alone does not change Chosen's appearance.

If your build compiles the distributed Sass, override its !default variables before loading Chosen:

@use "chosen-jjj/sass/chosen" with (
  $chosen-text-color: #263238,
  $chosen-active-color: #2563eb,
  $chosen-border-color: #8896a5
);

Use CSS custom properties for runtime theme switching. Sass variables set compile-time defaults.

Relative sizing

Chosen keeps its familiar pixel defaults. Scope relative values to a form when its controls should follow the root font size:

.relative-form .chosen-container {
  --chosen-font-size: 1rem;
  --chosen-control-line-height: 1.5rem;
  --chosen-control-padding-block: 0.3rem;
  --chosen-search-padding-inline-end: 2rem;
  --chosen-result-padding-block: 0.35rem;
  --chosen-icon-size: 1rem;
}

The embedded SVG icons scale with --chosen-icon-size (15px by default). Try the jQuery demo or Prototype demo.

A Chosen dropdown with relative text, spacing, and SVG icon sizes

Editing the control icons

The four source SVGs for the chevrons, search, clear, and active-clear icons ship with the repository and npm package. Edit one under sass/icons/ and run npm run build in a source checkout. The build embeds the edited SVG in the Sass defaults and generated CSS, so the default stylesheet still needs no separate image requests.

For an application-only override, set the corresponding --chosen-icon-chevrons, --chosen-icon-search, --chosen-icon-clear, or --chosen-icon-clear-active CSS variable to a url(...) image. The Options page lists these variables alongside the other theme settings.

Useful selectors

Part Selector
Generated wrapper .chosen-container
Closed single control .chosen-single
Multiple selection area .chosen-choices
Dropdown .chosen-drop
Search field .chosen-search input
Results list .chosen-results
Active result .active-result
Highlighted result .highlighted
Selected result .result-selected
Selected multiple choice .search-choice
Selected-choice summary .chosen-choice-summary
Removable selected result .chosen-result-deselectable
Select all / Deselect all row [data-chosen-action]
Results announcement .chosen-results-status
Disabled instance .chosen-disabled
Readonly instance .chosen-readonly
Open / active instance .chosen-with-drop / .chosen-container-active

Scope styles to one control

A select with id="project-members" receives a generated container with id="project_members_chosen". Punctuation is changed to underscores before the _chosen suffix is added.

#project_members_chosen .chosen-single {
  min-height: 36px;
}

You can also set inherit_select_classes: true and scope styles through an application class copied from the native select.

Search highlighting

Matched text uses an <em> element inside each result. Change its appearance without changing search behavior:

.chosen-container .chosen-results li em {
  font-style: normal;
  font-weight: 700;
  text-decoration: none;
}

The SCSS source exposes variables for highlight font style, weight, and decoration.

Dark mode

For application themes, override the control, dropdown, inputs, results, choices, and state colors together. Do not change only the page background; Chosen’s dropdown and search input have their own backgrounds and borders.

Use the maintained demo’s dark rules in docs/docsupport/style.css as a complete example.

CSS-controlled width

Chosen measures the native select and sets the generated container's width by default. Pass width: false to leave that width unset and size the container with a stylesheet instead:

$("#project").chosen({width: false});
#project_chosen {
  width: 24rem;
  max-width: 100%;
}

This works in both the jQuery and Prototype adapters. The container still receives the usual chosen-container class and an ID based on the select's ID. recalculate_width_on_update will not replace the CSS width. This setting removes the container's inline width only; other Chosen behavior can still set inline styles, so it does not by itself make a strict style-src Content Security Policy work. Try the live CSS width example.

Layout problems

If the source select is hidden when Chosen initializes, pass an explicit width or use width: false with a CSS width. Use dropdown_width when the result menu should be wider than the closed control. An explicitly sized dropdown floats as a separate surface; dropdown_width: "100%" intentionally keeps the same width while retaining that detached treatment. Customize its separation and elevation with --chosen-floating-dropdown-gap and --chosen-floating-dropdown-shadow.

By default, the dropdown stays positioned beneath its Chosen control. If an ancestor with overflow: hidden clips it, opt into fixed positioning:

$("#project").chosen({dropdown_position: "fixed"});

The dropdown stays aligned as the page or a containing element scrolls and when the window resizes. A transformed or paint-contained ancestor can still clip a fixed descendant; remove that ancestor style or use another layout in that case. Try the live clipping example.

Fixed dropdown visible below a clipped panel

Clone this wiki locally