A native select whose option list is drawn in the same material.
On this page
Use .select directly on a native <select>. The browser keeps the keys, type-ahead and the form value; the class draws the well and a quiet chevron that reads in both themes. Where the browser supports the customizable select, the option list is drawn in the same material as the rest of the interface.
With appearance: base-select the list is no longer drawn by the operating system. It becomes ::picker(select), a popover that the browser anchors to the control and flips at the viewport edge, and the stylesheet gives it the floating sheet, whose corner is a row's corner plus the 4px between them. Put select-option on each <option>:
The row under the pointer or the arrow keys takes a chip tone.
The current option carries a check at its end, drawn on ::checkmark.
The control's chevron is ::picker-icon; it turns over while the list is open.
A browser without the customizable select ignores all of this and shows the platform's own list, as it always has. Nothing in the markup changes, and select-option does no harm there.
/* * Select: a native <select> drawn as a well, or as a raised control in toolbars. * Where the browser supports appearance: base-select, the option list becomes a floating sheet in the same * material: options are rows with a concentric corner and the current one carries a check. Elsewhere the * select keeps the platform's own list. */@layer components {.select{--select-height:2.375rem;--select-padding-x:.75rem;--select-font-size:.875rem;--select-radius:var(--radius-control);-webkit-tap-highlight-color:transparent;/* A neutral mid-grey chevron reads on moonstone and obsidian alike. */--select-indicator:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23888' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4.5 6.5 3.5 3.5 3.5-3.5'/%3E%3C/svg%3E");min-width:0;min-height:var(--select-height);max-width:100%;margin:0;padding-block:0;padding-inline:var(--select-padding-x)calc(var(--select-padding-x)+1.25rem);border:0;border-radius:calc(var(--select-radius)*var(--corner-scale));corner-shape:var(--corner-shape);background:var(--select-indicator)no-repeatrightcalc(var(--select-padding-x)-.125rem)center/14px,var(--color-surface-inset);color:var(--color-text-strong);box-shadow:var(--shadow-pressed);font:400var(--select-font-size)/1.45var(--font-family-sans);font-feature-settings:inherit;text-overflow:ellipsis;appearance:none;cursor:pointer;transition-property: box-shadow, background-color;transition-duration:var(--duration-quick);transition-timing-function:var(--easing-glide);@media(hover:hover){&:hover:not(:focus-visible,:disabled){background-color:var(--color-surface-inset-hover);}}/* * Focused, or open. :open stays inside :is(), which forgives a browser that does not know it; a :not(:open) * on the hover rule would drop that rule there. This rule matches hover's weight and follows it instead, * so an open select keeps its raised face under the pointer. */&:is(:focus-visible,:open):not(:disabled){outline:none;background-color:var(--color-surface-raised);box-shadow:inset000.5pxvar(--color-line-mark),000.5pxvar(--color-line-mark),0003.5pxvar(--color-focus-halo);}&:disabled{color:var(--color-text-disabled);cursor:not-allowed;}/* The chevron stands at the end of the words, whichever way they run. */&:dir(rtl){background-position:leftcalc(var(--select-padding-x)-.125rem)center,00;}/* Raised: a control on a sheet, for toolbars and filters, matching the button beside it. */&.select-raised{background:var(--select-indicator)no-repeatrightcalc(var(--select-padding-x)-.125rem)center/14px,linear-gradient(180deg,var(--color-surface-raised),var(--color-surface-raised-low))var(--color-surface-raised-low);box-shadow:var(--shadow-raised);/* Its face is a gradient: swap backgrounds instantly, as a button does. */transition-property: box-shadow;font-weight:var(--font-weight-control);@media(hover:hover){&:hover:not(:focus-visible,:disabled){box-shadow:var(--shadow-raised-hover);}}&:is(:focus-visible,:open):not(:disabled){box-shadow:var(--shadow-raised);}&:focus-visible{@apply--focus-ring;}&:disabled{background-color:var(--color-surface-inset);background-image:var(--select-indicator);box-shadow:var(--shadow-flat);}}/* A select is as tall as the button and the field beside it: 32, 38 and 44px. */&.select-sm{--select-height:2rem;--select-padding-x:.625rem;--select-font-size:.8125rem;--select-radius:var(--radius-control-sm);}&.select-lg{--select-height:2.75rem;--select-padding-x:.875rem;--select-font-size:1rem;--select-radius:var(--radius-control-lg);}@media(pointer:coarse){min-height:max(var(--select-height),2.75rem);font-size:max(var(--select-font-size),1rem);}@media(forced-colors:active){outline:1pxsolid FieldText;outline-offset:-1px;&:is(:focus-visible,:open){outline:2pxsolid Highlight;outline-offset:-2px;}}}/* * The customizable select. The control becomes a flex row whose chevron is ::picker-icon, and the list is * ::picker(select): a popover the browser anchors to the control and flips at the viewport edge. */@supports(appearance: base-select){.select{display:inline-flex;align-items:center;justify-content:space-between;gap:.5rem;padding-block:0;padding-inline:var(--select-padding-x)calc(var(--select-padding-x)-.125rem);background:var(--color-surface-inset);appearance: base-select;&::picker-icon{content:'';flex:none;width:14px;height:14px;background:var(--color-text-muted);mask:var(--select-indicator)center/containno-repeat;transition: rotate var(--duration-base)var(--easing-glide);}&:open::picker-icon{rotate:x180deg;}&:disabled::picker-icon{background:var(--color-text-disabled);}&.select-raised{@apply--surface-sheet;&:disabled{background:var(--color-surface-inset);}}/* The list: a floating sheet 6px from the control, whose corner is a row's corner plus its 4px inset. */&::picker(select){margin:6px0;padding:4px;border:0;border-radius:calc(var(--radius-control-sm)*var(--corner-scale)+4px);corner-shape:var(--corner-shape);background:var(--color-surface-floating);color:var(--color-text-strong);box-shadow:var(--shadow-floating);font:400var(--select-font-size)/1.2var(--font-family-sans);scrollbar-width:thin;appearance: base-select;opacity:0;scale:.97;transform-origin:top;transition-property: opacity, scale,overlay, display;transition-duration:var(--duration-quick);transition-timing-function:var(--easing-glide);transition-behavior: allow-discrete;}&:open::picker(select){opacity:1;scale:1;@starting-style{opacity:0;scale:.97;}}@media(prefers-reduced-motion:reduce){&::picker-icon{transition:none;}&::picker(select),&:open::picker(select){scale:none;@starting-style{scale:none;}}}@media(forced-colors:active){&::picker-icon{background: FieldText;}&::picker(select){border:1pxsolid CanvasText;}}}/* An option in the list. The row under the pointer or the keys takes a chip tone; the current one a check. */.select-option{display:flex;align-items:center;gap:.5rem;min-height:2rem;padding:0.5rem;border-radius:calc(var(--radius-control-sm)*var(--corner-scale));corner-shape:var(--corner-shape);outline:none;background:transparent;color:var(--color-text-strong);white-space:nowrap;cursor:pointer;&::checkmark{content:'';order:1;flex:none;width:14px;height:14px;margin-inline-start:auto;background:currentColor;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m3.5 8.5 3 3 6-7'/%3E%3C/svg%3E")center/containno-repeat;}&:focus-visible:not(:disabled){background:var(--color-surface-chip);}@media(hover:hover){&:hover:not(:disabled){background:var(--color-surface-chip);}}/* Pressed: a step deeper than the pointer's tone. */&:active:not(:disabled){background:var(--color-surface-inset-hover);}&:disabled{color:var(--color-text-disabled);cursor:not-allowed;}@media(pointer:coarse){min-height:2.75rem;}@media(forced-colors:active){&:is(:hover,:focus-visible):not(:disabled){background: Highlight;color: HighlightText;}&::checkmark{background: CanvasText;}}}}}