Public
Edited
Jun 8
Paused
Insert cell
Insert cell
Insert cell
data = d3.groups(citywages, d => d.state_display)
Insert cell
viewof selected = htl.html`<select onclick=${onOptgroupClick} multiple=true size=15 style="resize:vertical">${
data.map(([parent, children]) => htl.html`<optgroup label=${parent}>${
children.map(({nyt_display: value}) => htl.html`<option value="${value}">${value}`)
}`)
}`
Insert cell
selected
Insert cell
function onOptgroupClick(e) {
if(e.target.localName !== "optgroup") return;
const optgroup = e.target;
const select = optgroup.parentElement;
const offset = select.scrollTop;
const children = [...optgroup.children];
const asSelected = children.some(c => !c.selected);
if(!e.metaKey) for(const c of [...select.selectedOptions]) c.selected = false;
for(const c of children) c.selected = asSelected;
select.dispatchEvent(new Event("input"), {bubbles: true});
// Chrome will automatically scroll to the first selected element, so we need to
// restore the scroll offset.
// Note that requestAnimationFrame won't do the trick, we *have* to use setTimeout.
setTimeout(() => (select.scrollTop = offset), 0);
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more