Welcome to Vanilla Breeze
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
Dropdown menu for choosing from a list of predefined options. Vanilla Breeze resets the native appearance and adds a custom SVG chevron, consistent sizing, and focus styling via design tokens.
Consider alternatives:
Basic select, optgroup categorization, multiple selection, and disabled states.
<label for="country">Country</label><select id="country" name="country"> <option value="">Select a country...</option> <option value="us">United States</option> <option value="ca">Canada</option> <option value="uk">United Kingdom</option></select>
Organize options into categories using optgroup.
<select id="product"> <option value="">Select a product...</option> <optgroup label="Electronics"> <option value="laptop">Laptop</option> <option value="phone">Smartphone</option> </optgroup> <optgroup label="Accessories"> <option value="case">Phone Case</option> <option value="charger">Charger</option> </optgroup></select>
Allow selecting multiple options with the multiple attribute. Use size to control how many options are visible.
<select multiple size="5"> <option value="html">HTML</option> <option value="css">CSS</option> <option value="js">JavaScript</option> <option value="python">Python</option> <option value="rust">Rust</option></select>
Disable the entire select or individual options within it.
<!-- Entire select disabled --><select disabled> <option>Cannot change</option></select> <!-- Individual option disabled --><select> <option value="free">Free</option> <option value="pro">Pro - $29/mo</option> <option value="enterprise" disabled>Enterprise (Contact us)</option></select>
| Attribute | Purpose | Example |
|---|---|---|
name |
Form field name for submission | name="country" |
required |
Field must have a non-empty value | required |
disabled |
Prevents selection | disabled |
multiple |
Allow selecting multiple options | multiple |
size |
Number of visible options (useful with multiple) |
size="5" |
autocomplete |
Autofill hint | autocomplete="country" |
Wrap a select in the form-field custom element for enhanced validation, required indicators, and helper text.
<form-field> <label for="department">Department</label> <select id="department" name="department" required> <option value="" disabled selected>Select department...</option> <option value="sales">Sales</option> <option value="engineering">Engineering</option> </select></form-field>
for/idautocomplete values for autofill (e.g., country)VB sets appearance: none to remove the native dropdown arrow and replaces it with a custom SVG chevron positioned via background-image. The select inherits shared input styles (border, radius, focus ring) from the form layer.
/* Select inherits shared input styles, then overrides: */ select { appearance: none; padding-inline-end: var(--size-xl); background-image: url("data:image/svg+xml,...chevron-svg..."); background-repeat: no-repeat; background-position: right var(--size-xs) center; background-size: 1.25rem; cursor: pointer;} select:disabled { cursor: not-allowed;} /* Multiple select removes the custom chevron */select[multiple] { padding: var(--size-xs);} optgroup { font-weight: 600;}
Chrome 135+ ships appearance: base-select, which unlocks full CSS control over the dropdown picker, options, checkmark icon, and open/close animations — while retaining native semantics, keyboard navigation, form participation, and accessibility.
VB wraps all customizable-select styles in @supports (appearance: base-select), making this a zero-risk progressive enhancement. Non-supporting browsers keep the existing appearance: none + SVG chevron.
--color-interactiveprefers-reduced-motion)<optgroup> headers render as uppercase muted section labels with dividersNo markup changes are required — every existing <select> upgrades automatically.
For selects with images, icons, or descriptions inside options, add a <button> trigger with <selectedcontent> to mirror the selected option in the closed state.
<select name="language"> <button> <selectedcontent></selectedcontent> </button> <option value="en"> <span aria-hidden="true">🇺🇸</span> English <span class="detail"> — American English</span> </option> <option value="es"> <span aria-hidden="true">🇪🇸</span> Español <span class="detail"> — Spanish</span> </option> <option value="fr"> <span aria-hidden="true">🇫🇷</span> Français <span class="detail"> — French</span> </option></select>
<button> becomes the trigger — VB styles it as a flex container<selectedcontent> automatically clones the selected option's contentclass="detail" are hidden in the closed trigger to keep it compact1.5em with border-radius and object-fit: coverThe base-select value exposes these pseudo-elements and states:
| Selector | What It Targets |
|---|---|
::picker(select) |
The dropdown popup container |
::picker-icon |
The built-in chevron arrow |
::checkmark |
The selected-option indicator |
:open |
Select while picker is visible |
selectedcontent |
Cloned content of selected option in trigger |
Use this table to decide between the native customizable select and VB's combo-box web component.
| Capability | Customizable Select | combo-box |
|---|---|---|
| JavaScript required | No | Yes |
| Filterable / searchable | No (type-ahead only) | Yes |
| Rich content in options | Yes (images, icons, text) | Yes |
| Form participation | Native | Manual (hidden input) |
| Browser support | Chrome 135+ | All modern browsers |
| Styled dropdown | Yes (with @supports gate) | Yes |
appearance: base-select ships in Chrome 135 (April 2025). Other browsers are implementing it — check caniuse for current status.
VB's implementation is fully gated behind @supports:
@supports (appearance: base-select) { select:not([multiple]) { appearance: base-select; /* ... all customizations ... */ }} /* Non-supporting browsers keep: */select { appearance: none; background-image: var(--select-chevron);}
Detect in JavaScript:
if (CSS.supports('appearance', 'base-select')) { // Customizable select is active}