A polished sort dropdown that unfurls from a compact pill into a luminous glass menu. Choosing the already-selected option triggers a rich confirmation ripple before the control folds back into its original resting state.
<!doctype html>
<html lang='en'>
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Glassy sort dropdown</title>
<link rel="stylesheet" href="halo-sort-dropdown.css" />
</head>
<body>
<div class='sort-shell'>
<button class='sort-trigger' type='button' aria-haspopup='listbox' aria-expanded='false' aria-label='Sort results'>
<span class='trigger-flash' aria-hidden='true'></span>
<span class='trigger-copy'>
<span class='trigger-kicker'>Sort by</span>
<span class='current-label'>Latest</span>
</span>
<span class='trigger-side' aria-hidden='true'>
<svg class='chevron' viewBox='0 0 20 20' fill='none'>
<path d='M5 7.5L10 12.5L15 7.5' stroke='currentColor' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'></path>
</svg>
</span>
</button>
<span class='accent-channel' aria-hidden='true'></span>
<div class='panel-sheen' aria-hidden='true'></div>
<span class='accent-orb' aria-hidden='true'></span>
<div class='panel' role='listbox' aria-label='Sort options' aria-hidden='true'>
<button class='option selected' type='button' role='option' aria-selected='true' data-value='Latest'>
<span class='option-text'>
<span class='option-title'>Latest</span>
<span class='option-note'>Newest arrivals first</span>
</span>
<span class='option-trace' aria-hidden='true'><span class='trace-bar'></span><span class='trace-bar'></span><span class='trace-bar'></span></span>
</button>
<button class='option' type='button' role='option' aria-selected='false' data-value='Popular'>
<span class='option-text'>
<span class='option-title'>Popular</span>
<span class='option-note'>Trending across the shop</span>
</span>
<span class='option-trace' aria-hidden='true'><span class='trace-bar'></span><span class='trace-bar'></span><span class='trace-bar'></span></span>
</button>
<button class='option' type='button' role='option' aria-selected='false' data-value='Price: Low to High'>
<span class='option-text'>
<span class='option-title'>Price: Low to High</span>
<span class='option-note'>Budget-friendly first</span>
</span>
<span class='option-trace' aria-hidden='true'><span class='trace-bar'></span><span class='trace-bar'></span><span class='trace-bar'></span></span>
</button>
<button class='option' type='button' role='option' aria-selected='false' data-value='Price: High to Low'>
<span class='option-text'>
<span class='option-title'>Price: High to Low</span>
<span class='option-note'>Premium picks on top</span>
</span>
<span class='option-trace' aria-hidden='true'><span class='trace-bar'></span><span class='trace-bar'></span><span class='trace-bar'></span></span>
</button>
</div>
</div>
<script src="halo-sort-dropdown.js"></script>
</body>
</html>
:root{--bg:#0f172a;--text:#e2e8f0;--line:rgba(255,255,255,.15);--selection-y:101px}*{box-sizing:border-box}html,body{width:100%;height:100%;margin:0}body{display:flex;align-items:center;justify-content:center;background:var(--bg);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;overflow:hidden}button{font:inherit;-webkit-tap-highlight-color:transparent}.sort-shell{position:relative;width:288px;height:68px;overflow:hidden;border-radius:34px;background:linear-gradient(180deg,rgba(255,255,255,.12),rgba(255,255,255,.045)),rgba(15,23,42,.58);border:1px solid rgba(255,255,255,.15);box-shadow:0 20px 42px rgba(2,6,23,.38),inset 0 1px 0 rgba(255,255,255,.13);backdrop-filter:blur(24px) saturate(150%);-webkit-backdrop-filter:blur(24px) saturate(150%);transition:height 720ms cubic-bezier(.22,1,.36,1),border-radius 720ms cubic-bezier(.22,1,.36,1),box-shadow 620ms cubic-bezier(.22,1,.36,1),transform 420ms ease}.sort-shell::before{content:'';position:absolute;inset:0;background:linear-gradient(180deg,rgba(255,255,255,.14),rgba(255,255,255,0) 44%),radial-gradient(circle at 14% -12%,rgba(125,211,252,.16),transparent 40%),radial-gradient(circle at 84% 8%,rgba(59,130,246,.12),transparent 32%);pointer-events:none}.sort-shell::after{content:'';position:absolute;inset:52px 10px 10px;border-radius:22px;background:linear-gradient(180deg,rgba(255,255,255,.06),rgba(255,255,255,.02)),radial-gradient(circle at 22% 0%,rgba(125,211,252,.12),transparent 48%);opacity:0;transform:translateY(-16px) scaleY(.36);transform-origin:top center;transition:opacity 360ms ease,transform 720ms cubic-bezier(.22,1,.36,1);pointer-events:none}.sort-shell.is-open{height:300px;border-radius:28px;box-shadow:0 28px 54px rgba(2,6,23,.42),inset 0 1px 0 rgba(255,255,255,.16)}.sort-shell.is-open::after{opacity:1;transform:translateY(0) scaleY(1)}.sort-shell.is-opening{transform:translateY(-1px)}.accent-channel{position:absolute;z-index:1;left:15px;top:15px;width:14px;height:calc(100% - 30px);border-radius:999px;background:linear-gradient(180deg,rgba(255,255,255,.11),rgba(255,255,255,.03)),rgba(255,255,255,.015);box-shadow:inset 0 1px 0 rgba(255,255,255,.06),inset 0 0 0 1px rgba(255,255,255,.035);pointer-events:none}.accent-channel::after{content:'';position:absolute;left:50%;top:11px;width:2px;height:calc(100% - 22px);transform:translateX(-50%);border-radius:999px;background:linear-gradient(180deg,rgba(125,211,252,.24),rgba(125,211,252,.05));opacity:.75}.sort-trigger{position:relative;z-index:3;width:100%;height:68px;padding:0 16px 0 42px;border:0;background:transparent;color:var(--text);display:flex;align-items:center;justify-content:space-between;cursor:pointer;isolation:isolate}.trigger-flash{position:absolute;inset:8px 54px 8px 34px;border-radius:26px;background:linear-gradient(90deg,rgba(125,211,252,0),rgba(125,211,252,.08) 28%,rgba(224,242,254,.26) 50%,rgba(125,211,252,.08) 68%,rgba(125,211,252,0));opacity:0;transform:translateX(-28px) scaleX(.78);transform-origin:left center;pointer-events:none}.trigger-copy{position:relative;z-index:1;display:flex;flex-direction:column;align-items:flex-start;gap:3px;min-width:0;max-width:176px;text-align:left}.trigger-kicker{font-size:11px;line-height:1;letter-spacing:.08em;text-transform:uppercase;color:rgba(196,208,224,.82);transition:color 240ms ease}.current-label{position:relative;max-width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-size:17px;line-height:1.1;font-weight:620;letter-spacing:-.01em;color:#f8fafc;transition:transform 380ms ease,letter-spacing 380ms ease,text-shadow 300ms ease}.current-label::after{content:'';position:absolute;inset:-4px -12px;border-radius:12px;background:linear-gradient(100deg,rgba(125,211,252,0) 14%,rgba(125,211,252,.16) 44%,rgba(224,242,254,.42) 52%,rgba(125,211,252,.1) 60%,rgba(125,211,252,0) 86%);opacity:0;transform:translateX(-32px) skewX(-18deg);pointer-events:none;mix-blend-mode:screen}.sort-shell.is-open .current-label{transform:translateY(1px);letter-spacing:.005em}.trigger-side{position:relative;z-index:1;display:flex;align-items:center;justify-content:center;width:46px;height:38px;border-radius:19px;border:1px solid rgba(255,255,255,.1);background:rgba(255,255,255,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.07);color:#dbeafe;transition:background 300ms ease,border-color 300ms ease,box-shadow 300ms ease}.chevron{width:18px;height:18px;opacity:.88;transform:rotate(0deg);transition:transform 500ms cubic-bezier(.22,1,.36,1),opacity 280ms ease}.sort-shell.is-open .chevron{transform:rotate(180deg);opacity:1}.panel-sheen{position:absolute;inset:66px 18px auto 18px;height:90px;border-radius:22px;background:radial-gradient(circle at 24% 20%,rgba(224,242,254,.14),transparent 38%),linear-gradient(180deg,rgba(255,255,255,.07),rgba(255,255,255,0));opacity:0;transform:translateY(-18px) scaleY(.24);transform-origin:top;filter:blur(10px);transition:opacity 360ms ease,transform 680ms cubic-bezier(.22,1,.36,1);pointer-events:none}.sort-shell.is-open .panel-sheen{opacity:1;transform:translateY(0) scaleY(1)}.accent-orb{position:absolute;z-index:4;left:18px;top:30px;width:8px;height:8px;border-radius:999px;background:radial-gradient(circle at 35% 35%,#e0f2fe,#7dd3fc 54%,#0ea5e9 78%);box-shadow:0 0 0 4px rgba(125,211,252,.04),0 0 12px rgba(56,189,248,.34),0 0 20px rgba(59,130,246,.16);transition:top 660ms cubic-bezier(.22,1,.36,1),left 660ms cubic-bezier(.22,1,.36,1),box-shadow 320ms ease,transform 320ms ease;pointer-events:none}.sort-shell.is-open .accent-orb{top:var(--selection-y);left:18px;box-shadow:0 0 0 6px rgba(125,211,252,.05),0 0 16px rgba(56,189,248,.5),0 0 28px rgba(59,130,246,.24)}.panel{position:absolute;inset:64px 10px 10px;padding:10px;display:flex;flex-direction:column;gap:6px;pointer-events:none}.sort-shell.is-open .panel{pointer-events:auto}.sort-shell.is-confirming .panel,.sort-shell.is-collapsing .panel{pointer-events:none}.option{position:relative;display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;height:46px;padding:0 14px 0 26px;border:0;border-radius:16px;background:rgba(255,255,255,.02);color:var(--text);text-align:left;opacity:0;transform:translateY(-14px) scale(.97);filter:blur(7px);pointer-events:none;transition:opacity 260ms ease,transform 600ms cubic-bezier(.22,1,.36,1),filter 600ms ease,background 280ms ease,color 280ms ease,box-shadow 280ms ease;overflow:hidden;cursor:pointer}.option::before{content:'';position:absolute;inset:0;background:linear-gradient(90deg,rgba(125,211,252,.18),rgba(56,189,248,.04) 42%,rgba(255,255,255,.02));opacity:0;transition:opacity 240ms ease}.option::after{content:'';position:absolute;width:18px;height:18px;border-radius:999px;left:calc(50% - 9px);top:calc(50% - 9px);background:radial-gradient(circle,rgba(125,211,252,.44),rgba(125,211,252,.12) 45%,rgba(125,211,252,0) 72%);transform:scale(.4);opacity:0;pointer-events:none}.sort-shell.is-open .option{pointer-events:auto;opacity:1;transform:translateY(0) scale(1);filter:blur(0)}.sort-shell.is-open .option:nth-of-type(1){transition-delay:70ms}.sort-shell.is-open .option:nth-of-type(2){transition-delay:135ms}.sort-shell.is-open .option:nth-of-type(3){transition-delay:200ms}.sort-shell.is-open .option:nth-of-type(4){transition-delay:265ms}.sort-shell.is-confirming .option:not(.is-confirmed){opacity:.72;transform:translateY(0) scale(.995)}.sort-shell.is-confirming .option.is-confirmed{background:rgba(255,255,255,.11);box-shadow:inset 0 0 0 1px rgba(125,211,252,.18),0 0 0 1px rgba(255,255,255,.02)}.sort-shell.is-collapsing .option:not(.is-confirmed){opacity:0;transform:translateY(-12px) scale(.96);filter:blur(6px);transition-duration:160ms,220ms,220ms,220ms,220ms,220ms}.sort-shell.is-collapsing .option.is-confirmed{opacity:.86;transform:translateY(-4px) scale(.985);transition-duration:180ms,260ms,260ms,220ms,220ms,220ms}.option-text{position:relative;z-index:1;display:flex;flex-direction:column;gap:3px;min-width:0}.option-title{font-size:16px;line-height:1.1;font-weight:600;letter-spacing:-.01em;color:inherit;white-space:nowrap}.option-note{font-size:12px;line-height:1;color:rgba(148,163,184,.94);white-space:nowrap}.option-trace{position:relative;z-index:1;display:flex;align-items:center;gap:4px;color:rgba(191,219,254,.88)}.trace-bar{display:block;height:3px;border-radius:999px;background:currentColor;opacity:.8}.trace-bar:nth-child(1){width:12px}.trace-bar:nth-child(2){width:17px}.trace-bar:nth-child(3){width:8px}.option.selected{background:rgba(255,255,255,.082);color:#f8fafc;box-shadow:inset 0 0 0 1px rgba(125,211,252,.12)}.option.selected::before{opacity:1}.option.selected .option-note{color:rgba(191,219,254,.92)}.option.is-confirmed::after{animation:row-pulse 720ms cubic-bezier(.18,.9,.2,1) both}.sort-shell.is-confirming .accent-orb{animation:orb-confirm 900ms cubic-bezier(.32,.72,.17,1) both}.sort-shell.is-confirming .trigger-flash{animation:trigger-flash 760ms cubic-bezier(.2,.9,.18,1) both}.sort-shell.is-confirming .current-label{animation:label-confirm 760ms cubic-bezier(.2,.9,.18,1) both}.sort-shell.is-confirming .current-label::after{animation:label-sheen 700ms ease both}.sort-shell.is-confirming .trigger-kicker{animation:kicker-confirm 620ms ease both}.sort-shell.is-confirming .trigger-side{animation:side-confirm 780ms cubic-bezier(.2,.9,.18,1) both}.sort-shell.is-confirming .chevron{animation:chevron-settle 620ms cubic-bezier(.22,1,.36,1) both}@keyframes row-pulse{0%{opacity:0;transform:scale(.4)}24%{opacity:1;transform:scale(3.6)}100%{opacity:0;transform:scale(7.2)}}@keyframes orb-confirm{0%{left:18px;top:var(--selection-y);transform:scale(1);box-shadow:0 0 0 6px rgba(125,211,252,.05),0 0 16px rgba(56,189,248,.5),0 0 28px rgba(59,130,246,.24)}22%{left:70px;top:var(--selection-y);transform:scale(1.16)}48%{left:236px;top:var(--selection-y);transform:scale(1.02);box-shadow:0 0 0 10px rgba(125,211,252,.08),0 0 24px rgba(56,189,248,.62),0 0 34px rgba(59,130,246,.3)}74%{left:150px;top:31px;transform:scale(.94)}100%{left:18px;top:30px;transform:scale(1);box-shadow:0 0 0 4px rgba(125,211,252,.04),0 0 12px rgba(56,189,248,.34),0 0 20px rgba(59,130,246,.16)}}@keyframes trigger-flash{0%{opacity:0;transform:translateX(-28px) scaleX(.78)}24%{opacity:.88}100%{opacity:0;transform:translateX(12px) scaleX(1.03)}}@keyframes label-confirm{0%{transform:translateX(0);letter-spacing:-.01em;text-shadow:0 0 0 rgba(125,211,252,0)}30%{transform:translateX(2px);letter-spacing:.02em;text-shadow:0 0 14px rgba(125,211,252,.36)}100%{transform:translateX(0);letter-spacing:-.01em;text-shadow:0 0 0 rgba(125,211,252,0)}}@keyframes label-sheen{0%{opacity:0;transform:translateX(-32px) skewX(-18deg)}24%{opacity:.94}100%{opacity:0;transform:translateX(42px) skewX(-18deg)}}@keyframes kicker-confirm{0%{color:rgba(196,208,224,.82)}34%{color:rgba(219,234,254,.96)}100%{color:rgba(196,208,224,.82)}}@keyframes side-confirm{0%{background:rgba(255,255,255,.05);border-color:rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.07);transform:scale(1)}36%{background:rgba(125,211,252,.14);border-color:rgba(191,219,254,.24);box-shadow:inset 0 1px 0 rgba(255,255,255,.14),0 0 0 5px rgba(125,211,252,.06),0 0 16px rgba(56,189,248,.18);transform:scale(1.04)}100%{background:rgba(255,255,255,.05);border-color:rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.07);transform:scale(1)}}@keyframes chevron-settle{0%{transform:rotate(180deg) scale(1)}56%{transform:rotate(-10deg) scale(1.1)}100%{transform:rotate(0deg) scale(1)}}
(function(){
var root=document.querySelector('.sort-shell');
var trigger=root.querySelector('.sort-trigger');
var label=root.querySelector('.current-label');
var panel=root.querySelector('.panel');
var options=Array.prototype.slice.call(root.querySelectorAll('.option'));
var timers=[];
var open=false;
var busy=false;
var OPEN_GLOW=660;
var CONFIRM_HOLD=920;
var CLOSE_TIME=760;
function schedule(fn,delay){
var id=setTimeout(fn,delay);
timers.push(id);
return id;
}
function clearTimers(){
timers.forEach(function(id){clearTimeout(id);});
timers=[];
}
function selectedOption(){
return root.querySelector('.option.selected')||options[0];
}
function updateSelectionGeometry(option){
var rootRect=root.getBoundingClientRect();
var optionRect=option.getBoundingClientRect();
var y=optionRect.top-rootRect.top+(optionRect.height/2)-4;
root.style.setProperty('--selection-y',y+'px');
}
function setSelected(option){
options.forEach(function(item){
var isSelected=item===option;
item.classList.toggle('selected',isSelected);
item.setAttribute('aria-selected',isSelected?'true':'false');
});
label.textContent=option.getAttribute('data-value');
updateSelectionGeometry(option);
}
function clearTransientClasses(){
root.classList.remove('is-opening','is-confirming','is-collapsing');
options.forEach(function(item){item.classList.remove('is-confirmed');});
}
function openMenu(){
if(open||busy){return;}
clearTimers();
clearTransientClasses();
open=true;
trigger.setAttribute('aria-expanded','true');
panel.setAttribute('aria-hidden','false');
updateSelectionGeometry(selectedOption());
root.classList.add('is-open','is-opening');
schedule(function(){root.classList.remove('is-opening');},OPEN_GLOW);
}
function startCollapse(){
open=false;
trigger.setAttribute('aria-expanded','false');
panel.setAttribute('aria-hidden','true');
root.classList.remove('is-open','is-opening');
root.classList.add('is-collapsing');
}
function finishClose(){
clearTimers();
startCollapse();
schedule(function(){
root.classList.remove('is-collapsing');
},CLOSE_TIME);
}
trigger.addEventListener('click',function(){
if(busy){return;}
if(open){
finishClose();
return;
}
openMenu();
});
options.forEach(function(option){
option.addEventListener('click',function(){
if(!open||busy){return;}
clearTimers();
busy=true;
root.classList.remove('is-opening');
setSelected(option);
option.classList.add('is-confirmed');
root.classList.add('is-confirming');
schedule(function(){
startCollapse();
},CONFIRM_HOLD);
schedule(function(){
clearTransientClasses();
busy=false;
},CONFIRM_HOLD+CLOSE_TIME);
});
});
requestAnimationFrame(function(){
setSelected(selectedOption());
panel.setAttribute('aria-hidden','true');
});
})();