Select Navigation (Internal) v1.8.0
Allow user to choose an item from a select menu, updating the content on the same page.
Default Setup Anchor (Default Setup)
User Interface Developer
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
Director, Accessibility
Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
Chief Cook & Bottle Washer
Pellentesque habitant Accessibility Director et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante.
- Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
- Aliquam tincidunt mauris eu risus.
- Vestibulum auctor dapibus neque.
<div class="select-internal">
<nav aria-label="Job Positions" class="select-internal__nav">
<label class="select-internal__label">Select your job position</label>
<select class="select-internal__select">
<option value="#uid">User Interface Developer</option>
<option value="#a11y-director">Director, Accessibility</option>
<option value="#chief-cook">Chief Cook & Bottle Washer</option>
</select>
<div class="visually-hidden" aria-live="polite"></div>
</nav>
<div class="select-internal__content" id="uid">
<h2>User Interface Developer</h2>
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, <a href="#">tempor sit amet</a>, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
</div>
<div class="select-internal__content" hidden id="a11y-director">
<h2>Director, Accessibility</h2>
<p>Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
</div>
<div class="select-internal__content" hidden id="chief-cook">
<h2>Chief Cook & Bottle Washer</h2>
<p>Pellentesque habitant <a href="#a11y-director">Accessibility Director</a> et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante.</p>
<ul>
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
<li>Aliquam tincidunt mauris eu risus.</li>
<li>Vestibulum auctor dapibus neque.</li>
</ul>
</div>
</div>/*!
Radancy Component Library: Select Navigation (Internal)
Contributor(s):
Michael "Spell" Spellacy
Dependencies: Sass
*/
.select-internal {
&__nav {
background-color: #eee;
border-radius: .5em;
display: grid;
gap: .5em;
max-inline-size: calc(420rem / 16);
padding: 1em;
}
&__label {
font-weight: bold;
margin: 0;
}
&__select {
background-color: #FFF;
border: 1px #ccc solid;
font-size: inherit;
padding: .5em;
inline-size: 100%;
}
&__content {
margin-block-start: 2em;
&:target {
scroll-margin-top: calc(190em / 16);
}
}
// Custom Select
&[data-custom-select] {
--select-primary-color: #6F00EF;
--select-border-radius: calc(5rem / 16);
.select-internal__select, ::picker(select) {
appearance: base-select;
line-height: normal;
}
.select-internal__select {
border-radius: var(--select-border-radius);
&:focus-visible {
outline: calc(2rem / 16) var(--select-primary-color) solid;
outline-offset: calc(2rem / 16);
}
&::picker-icon {
color: var(--select-primary-color);
transition: .4s rotate;
}
&:open::picker-icon {
rotate: 180deg;
}
optgroup {
option {
margin-inline-start: 1rem;
}
}
legend {
color: var(--select-primary-color);
margin-block: 1rem;
}
option {
border-radius: var(--select-border-radius);
margin-block-end: calc(8rem / 16);
padding: calc(8rem / 16) calc(8rem / 16) calc(8rem / 16) 1rem;
&::checkmark {
border-radius: 100vw;
border: calc(2rem / 16) #fff solid;
color: #fff;
font-weight: bold;
margin-inline-start: auto;
order: 1;
padding: calc(3rem / 16) calc(8rem / 16);
}
&[value=""] {
background-color: #eee;
&:not(:hover):not(:focus) {
&::checkmark {
border-color: #000;
color: #000;
}
}
}
&:focus, &:hover {
outline: 0;
color: #fff;
background-color: var(--select-primary-color);
}
}
}
// This is the select dropdown
::picker(select) {
border-radius: var(--select-border-radius);
border: calc(1rem / 16) #666 solid;
box-shadow: 0 calc(4rem / 16) calc(16rem / 16) rgb(0 0 0 / .8);
margin: 1rem 1rem 0 0;
padding: 1rem;
scrollbar-color: var(--select-primary-color) transparent;
scrollbar-width: thin;
}
}
}/*!
Radancy Component Library: Select Navigation (Internal)
Contributor(s):
Michael "Spell" Spellacy
*/
(function() {
"use strict";
// Display which component is in use via console:
console.log("%cSelect Navigation (Internal)%cv1.8.0", "background: #2d2d2d; color: #fff; padding: 6px 10px; border-radius: 16px 0 0 16px; font-weight: 600;" , "background: #6e00ee; color: #fff; padding: 6px 10px; border-radius: 0 16px 16px 0; font-weight: 600;");
var selectInternalClass = ".select-internal";
var selectInternalLabelClass = ".select-internal__label";
var selectInternalSelectClass = ".select-internal__select";
var selectInternalOptionClass = ".select-internal__select option";
var selectInternalContentClass = ".select-internal__content";
var selectInternalDataCustomAriaLive = "data-aria-live";
var selectInternal = document.querySelectorAll(selectInternalClass);
var selectInternalLabel = document.querySelectorAll(selectInternalLabelClass);
var selectInternalSelect = document.querySelectorAll(selectInternalSelectClass);
var selectInternalState = "active";
var selectInternalContentList = [];
// On page load
selectInternal.forEach(function(component) {
// Check if "dynamic" Jump Menu is in use.
if (component.hasAttribute("data-dynamic")) {
var selectInternalContent = component.querySelectorAll(selectInternalContentClass);
var selectInternalContentNth = component.querySelectorAll(selectInternalContentClass + ":nth-of-type(n + 2)");
selectInternalContentNth.forEach(function(content) {
content.setAttribute("hidden", "");
});
selectInternalContent.forEach(function(content, i) {
var count = i + 1;
// If custom ID present
var contentID = content.hasAttribute("data-id") ? content.getAttribute("data-id"): "content-" + count;
content.setAttribute("id", contentID);
// Create option element
var option = document.createElement("option");
option.setAttribute("value", "#" + contentID);
option.textContent = content.getAttribute("data-label");
// Append each dynamic option.
component.querySelector("select").appendChild(option);
});
}
});
var selectInternalOption = document.querySelectorAll(selectInternalOptionClass);
selectInternalLabel.forEach(function(label, e) {
// Apply "for" attribute to each label.
label.setAttribute("for", "select-internal-" + (e + 1));
});
selectInternalSelect.forEach(function(select, e) {
// Apply "id" to each select.
select.setAttribute("id", "select-internal-" + (e + 1));
});
// Get all Job Menu options on page and push to array.
selectInternalOption.forEach(function(option) {
selectInternalContentList.push(option.getAttribute("value"));
});
function selectInternalSelectedState() {
var selectInternalHash = location.hash || selectInternalContentList[0];
if (!selectInternalHash) {
return;
}
var selectInternalFragment = selectInternalHash.slice(1);
// Check array against hash
if (selectInternalContentList.includes(selectInternalHash)) {
// If hash matches one of the array selections, load the selected content in hash
var selectInternalSelected = document.getElementById(selectInternalFragment);
var selectInternalContent = selectInternalSelected.closest(selectInternalClass).querySelectorAll(selectInternalContentClass);
selectInternalContent.forEach(function(content) {
content.setAttribute("hidden", "");
});
selectInternalSelected.removeAttribute("hidden");
selectInternalOption.forEach(function(option) {
var optionValue = option.getAttribute("value");
if (location.hash === optionValue) {
option.setAttribute("selected", "");
option.closest(selectInternalClass).classList.add(selectInternalState);
} else {
option.removeAttribute("selected");
}
});
// Update select dropdown
var select = document.querySelector(selectInternalClass + " select");
if (select) {
select.value = selectInternalHash;
}
}
}
selectInternalSelectedState();
// Hash change event listener
window.addEventListener("hashchange", function() {
selectInternalSelectedState();
// When link is pressed, place programatic focus on selected content. This is useful if links are elsewhere on the page.
// If this causes issues elsewhere on page when haschange is fired, let me know.
var selectedContent = document.querySelector(selectInternalContentClass + ":not([hidden])");
var selectedContentID = selectedContent.getAttribute("id");
var URLHash = location.hash.slice(1);
if(URLHash === selectedContentID) {
selectedContent.setAttribute("tabindex", "-1");
selectedContent.focus();
}
});
selectInternalSelect.forEach(function(select) {
select.addEventListener("change", function() {
var selectInternalParent = this.closest(selectInternalClass);
var selectInternalContent = selectInternalParent.querySelectorAll(selectInternalContentClass);
// Send message to screen reader.
var selectInternalAnnounce = selectInternalParent.querySelector("div[aria-live]");
if(!selectInternalParent.hasAttribute(selectInternalDataCustomAriaLive)){
selectInternalAnnounce.textContent = "Selected Content: " + this.options[this.selectedIndex].text; // TODO: Tokenize for i18n.
}
// Update hash in URL
if (this.value === "") {
var urlWithoutHash = window.location.href.split("#")[0];
history.replaceState(null, null, urlWithoutHash);
selectInternalAnnounce.textContent = "";
} else {
history.replaceState(null, null, this.value);
}
selectInternalContent.forEach(function(content) {
content.setAttribute("hidden", "");
});
var selectInternalContentSelected = location.hash.slice(1);
document.getElementById(selectInternalContentSelected).removeAttribute("hidden");
// Set selected jump menu to active.
selectInternal.forEach(function(menu) {
menu.classList.remove(selectInternalState);
});
selectInternalParent.classList.add(selectInternalState);
});
});
// Fix for some browsers not resetting the select index on page unload.
window.addEventListener("beforeunload", function() {
selectInternal.forEach(function(menu) {
if (!menu.classList.contains(selectInternalState)) {
menu.querySelector("select").selectedIndex = 0;
}
});
});
})();Custom Aria-Live Setup Anchor (Custom Aria-Live Setup)
Harry Potter
Expecto Patronum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
Marvel
Pellentesque habitant morbi tristique senectus tempor sit amet, ante. Donec eu libero sit amet quam egestas 3000.
Star Trek
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, U.S.S. Enterprise, ante. Donec eu libero sit amet.
Star Wars
Senectus et netus et the force fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, Sidious, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
<div class="select-internal" data-aria-live>
<nav aria-label="Favorite Movies" class="select-internal__nav">
<label class="select-internal__label">Select your favorite movie franchise</label>
<select class="select-internal__select">
<option value="#harry-potter">Harry Potter</option>
<option value="#marvel">Marvel</option>
<option value="#star-trek">Star Trek</option>
<option value="#star-wars">Star Wars</option>
</select>
</nav>
<div aria-live="polite">
<div class="select-internal__content" id="harry-potter">
<h2>Harry Potter</h2>
<p>Expecto Patronum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
</div>
<div class="select-internal__content" hidden id="marvel">
<h2>Marvel</h2>
<p>Pellentesque habitant <a href="#!">morbi tristique senectus</a> tempor sit amet, ante. Donec eu libero sit amet quam egestas 3000.</p>
</div>
<div class="select-internal__content" hidden id="star-trek">
<h2>Star Trek</h2>
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, <a href="#!">U.S.S. Enterprise</a>, ante. Donec eu libero sit amet.</p>
</div>
<div class="select-internal__content" hidden id="star-wars">
<h2>Star Wars</h2>
<p>Senectus et netus et the force fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, <a href="#!">Sidious</a>, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
</div>
</div>
</div>/*!
Radancy Component Library: Select Navigation (Internal)
Contributor(s):
Michael "Spell" Spellacy
Dependencies: Sass
*/
.select-internal {
&__nav {
background-color: #eee;
border-radius: .5em;
display: grid;
gap: .5em;
max-inline-size: calc(420rem / 16);
padding: 1em;
}
&__label {
font-weight: bold;
margin: 0;
}
&__select {
background-color: #FFF;
border: 1px #ccc solid;
font-size: inherit;
padding: .5em;
inline-size: 100%;
}
&__content {
margin-block-start: 2em;
&:target {
scroll-margin-top: calc(190em / 16);
}
}
// Custom Select
&[data-custom-select] {
--select-primary-color: #6F00EF;
--select-border-radius: calc(5rem / 16);
.select-internal__select, ::picker(select) {
appearance: base-select;
line-height: normal;
}
.select-internal__select {
border-radius: var(--select-border-radius);
&:focus-visible {
outline: calc(2rem / 16) var(--select-primary-color) solid;
outline-offset: calc(2rem / 16);
}
&::picker-icon {
color: var(--select-primary-color);
transition: .4s rotate;
}
&:open::picker-icon {
rotate: 180deg;
}
optgroup {
option {
margin-inline-start: 1rem;
}
}
legend {
color: var(--select-primary-color);
margin-block: 1rem;
}
option {
border-radius: var(--select-border-radius);
margin-block-end: calc(8rem / 16);
padding: calc(8rem / 16) calc(8rem / 16) calc(8rem / 16) 1rem;
&::checkmark {
border-radius: 100vw;
border: calc(2rem / 16) #fff solid;
color: #fff;
font-weight: bold;
margin-inline-start: auto;
order: 1;
padding: calc(3rem / 16) calc(8rem / 16);
}
&[value=""] {
background-color: #eee;
&:not(:hover):not(:focus) {
&::checkmark {
border-color: #000;
color: #000;
}
}
}
&:focus, &:hover {
outline: 0;
color: #fff;
background-color: var(--select-primary-color);
}
}
}
// This is the select dropdown
::picker(select) {
border-radius: var(--select-border-radius);
border: calc(1rem / 16) #666 solid;
box-shadow: 0 calc(4rem / 16) calc(16rem / 16) rgb(0 0 0 / .8);
margin: 1rem 1rem 0 0;
padding: 1rem;
scrollbar-color: var(--select-primary-color) transparent;
scrollbar-width: thin;
}
}
}/*!
Radancy Component Library: Select Navigation (Internal)
Contributor(s):
Michael "Spell" Spellacy
*/
(function() {
"use strict";
// Display which component is in use via console:
console.log("%cSelect Navigation (Internal)%cv1.8.0", "background: #2d2d2d; color: #fff; padding: 6px 10px; border-radius: 16px 0 0 16px; font-weight: 600;" , "background: #6e00ee; color: #fff; padding: 6px 10px; border-radius: 0 16px 16px 0; font-weight: 600;");
var selectInternalClass = ".select-internal";
var selectInternalLabelClass = ".select-internal__label";
var selectInternalSelectClass = ".select-internal__select";
var selectInternalOptionClass = ".select-internal__select option";
var selectInternalContentClass = ".select-internal__content";
var selectInternalDataCustomAriaLive = "data-aria-live";
var selectInternal = document.querySelectorAll(selectInternalClass);
var selectInternalLabel = document.querySelectorAll(selectInternalLabelClass);
var selectInternalSelect = document.querySelectorAll(selectInternalSelectClass);
var selectInternalState = "active";
var selectInternalContentList = [];
// On page load
selectInternal.forEach(function(component) {
// Check if "dynamic" Jump Menu is in use.
if (component.hasAttribute("data-dynamic")) {
var selectInternalContent = component.querySelectorAll(selectInternalContentClass);
var selectInternalContentNth = component.querySelectorAll(selectInternalContentClass + ":nth-of-type(n + 2)");
selectInternalContentNth.forEach(function(content) {
content.setAttribute("hidden", "");
});
selectInternalContent.forEach(function(content, i) {
var count = i + 1;
// If custom ID present
var contentID = content.hasAttribute("data-id") ? content.getAttribute("data-id"): "content-" + count;
content.setAttribute("id", contentID);
// Create option element
var option = document.createElement("option");
option.setAttribute("value", "#" + contentID);
option.textContent = content.getAttribute("data-label");
// Append each dynamic option.
component.querySelector("select").appendChild(option);
});
}
});
var selectInternalOption = document.querySelectorAll(selectInternalOptionClass);
selectInternalLabel.forEach(function(label, e) {
// Apply "for" attribute to each label.
label.setAttribute("for", "select-internal-" + (e + 1));
});
selectInternalSelect.forEach(function(select, e) {
// Apply "id" to each select.
select.setAttribute("id", "select-internal-" + (e + 1));
});
// Get all Job Menu options on page and push to array.
selectInternalOption.forEach(function(option) {
selectInternalContentList.push(option.getAttribute("value"));
});
function selectInternalSelectedState() {
var selectInternalHash = location.hash || selectInternalContentList[0];
if (!selectInternalHash) {
return;
}
var selectInternalFragment = selectInternalHash.slice(1);
// Check array against hash
if (selectInternalContentList.includes(selectInternalHash)) {
// If hash matches one of the array selections, load the selected content in hash
var selectInternalSelected = document.getElementById(selectInternalFragment);
var selectInternalContent = selectInternalSelected.closest(selectInternalClass).querySelectorAll(selectInternalContentClass);
selectInternalContent.forEach(function(content) {
content.setAttribute("hidden", "");
});
selectInternalSelected.removeAttribute("hidden");
selectInternalOption.forEach(function(option) {
var optionValue = option.getAttribute("value");
if (location.hash === optionValue) {
option.setAttribute("selected", "");
option.closest(selectInternalClass).classList.add(selectInternalState);
} else {
option.removeAttribute("selected");
}
});
// Update select dropdown
var select = document.querySelector(selectInternalClass + " select");
if (select) {
select.value = selectInternalHash;
}
}
}
selectInternalSelectedState();
// Hash change event listener
window.addEventListener("hashchange", function() {
selectInternalSelectedState();
// When link is pressed, place programatic focus on selected content. This is useful if links are elsewhere on the page.
// If this causes issues elsewhere on page when haschange is fired, let me know.
var selectedContent = document.querySelector(selectInternalContentClass + ":not([hidden])");
var selectedContentID = selectedContent.getAttribute("id");
var URLHash = location.hash.slice(1);
if(URLHash === selectedContentID) {
selectedContent.setAttribute("tabindex", "-1");
selectedContent.focus();
}
});
selectInternalSelect.forEach(function(select) {
select.addEventListener("change", function() {
var selectInternalParent = this.closest(selectInternalClass);
var selectInternalContent = selectInternalParent.querySelectorAll(selectInternalContentClass);
// Send message to screen reader.
var selectInternalAnnounce = selectInternalParent.querySelector("div[aria-live]");
if(!selectInternalParent.hasAttribute(selectInternalDataCustomAriaLive)){
selectInternalAnnounce.textContent = "Selected Content: " + this.options[this.selectedIndex].text; // TODO: Tokenize for i18n.
}
// Update hash in URL
if (this.value === "") {
var urlWithoutHash = window.location.href.split("#")[0];
history.replaceState(null, null, urlWithoutHash);
selectInternalAnnounce.textContent = "";
} else {
history.replaceState(null, null, this.value);
}
selectInternalContent.forEach(function(content) {
content.setAttribute("hidden", "");
});
var selectInternalContentSelected = location.hash.slice(1);
document.getElementById(selectInternalContentSelected).removeAttribute("hidden");
// Set selected jump menu to active.
selectInternal.forEach(function(menu) {
menu.classList.remove(selectInternalState);
});
selectInternalParent.classList.add(selectInternalState);
});
});
// Fix for some browsers not resetting the select index on page unload.
window.addEventListener("beforeunload", function() {
selectInternal.forEach(function(menu) {
if (!menu.classList.contains(selectInternalState)) {
menu.querySelector("select").selectedIndex = 0;
}
});
});
})();Dynamic Option Elements Anchor (Dynamic Option Elements)
California
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
Abitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.
New York
Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
Pennsylvania
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante.
- Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
- Aliquam tincidunt mauris eu risus.
- Vestibulum auctor dapibus neque.
Senectus et netus et malesuada fames ac turpis egestas ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Senectus et netus et fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Senectus et netus et malesuada egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.
Experimental: Experimental examples or components may require additional work, further testing, and may not be fully supported or accessible. They should be carefully evaluated before being used in a production environment.
<div class="select-internal" data-dynamic>
<nav aria-label="Job Locations" class="select-internal__nav">
<label class="select-internal__label">Select your job location</label>
<select class="select-internal__select">
</select>
<div class="visually-hidden" aria-live="polite"></div>
</nav>
<div class="select-internal__content" data-label="California">
<h2>California</h2>
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, <a href="#">tempor sit amet</a>, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
<p><strong>Abitant morbi tristique</strong> senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. <em>Aenean ultricies mi vitae est.</em> Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. <a href="#">Donec non enim</a> in turpis pulvinar facilisis. Ut felis.</p>
</div>
<div class="select-internal__content" data-label="New York">
<h2>New York</h2>
<p>Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
</div>
<div class="select-internal__content" data-label="Pennsylvania">
<h2>Pennsylvania</h2>
<p>Pellentesque habitant <a href="#">morbi tristique senectus</a> et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante.</p>
<ul>
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
<li>Aliquam tincidunt mauris eu risus.</li>
<li>Vestibulum auctor dapibus neque.</li>
</ul>
<p>Senectus et netus et malesuada fames ac turpis egestas ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Senectus et netus et fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Senectus et netus et malesuada egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.</p>
</div>
</div>/*!
Radancy Component Library: Select Navigation (Internal)
Contributor(s):
Michael "Spell" Spellacy
Dependencies: Sass
*/
.select-internal {
&__nav {
background-color: #eee;
border-radius: .5em;
display: grid;
gap: .5em;
max-inline-size: calc(420rem / 16);
padding: 1em;
}
&__label {
font-weight: bold;
margin: 0;
}
&__select {
background-color: #FFF;
border: 1px #ccc solid;
font-size: inherit;
padding: .5em;
inline-size: 100%;
}
&__content {
margin-block-start: 2em;
&:target {
scroll-margin-top: calc(190em / 16);
}
}
// Custom Select
&[data-custom-select] {
--select-primary-color: #6F00EF;
--select-border-radius: calc(5rem / 16);
.select-internal__select, ::picker(select) {
appearance: base-select;
line-height: normal;
}
.select-internal__select {
border-radius: var(--select-border-radius);
&:focus-visible {
outline: calc(2rem / 16) var(--select-primary-color) solid;
outline-offset: calc(2rem / 16);
}
&::picker-icon {
color: var(--select-primary-color);
transition: .4s rotate;
}
&:open::picker-icon {
rotate: 180deg;
}
optgroup {
option {
margin-inline-start: 1rem;
}
}
legend {
color: var(--select-primary-color);
margin-block: 1rem;
}
option {
border-radius: var(--select-border-radius);
margin-block-end: calc(8rem / 16);
padding: calc(8rem / 16) calc(8rem / 16) calc(8rem / 16) 1rem;
&::checkmark {
border-radius: 100vw;
border: calc(2rem / 16) #fff solid;
color: #fff;
font-weight: bold;
margin-inline-start: auto;
order: 1;
padding: calc(3rem / 16) calc(8rem / 16);
}
&[value=""] {
background-color: #eee;
&:not(:hover):not(:focus) {
&::checkmark {
border-color: #000;
color: #000;
}
}
}
&:focus, &:hover {
outline: 0;
color: #fff;
background-color: var(--select-primary-color);
}
}
}
// This is the select dropdown
::picker(select) {
border-radius: var(--select-border-radius);
border: calc(1rem / 16) #666 solid;
box-shadow: 0 calc(4rem / 16) calc(16rem / 16) rgb(0 0 0 / .8);
margin: 1rem 1rem 0 0;
padding: 1rem;
scrollbar-color: var(--select-primary-color) transparent;
scrollbar-width: thin;
}
}
}/*!
Radancy Component Library: Select Navigation (Internal)
Contributor(s):
Michael "Spell" Spellacy
*/
(function() {
"use strict";
// Display which component is in use via console:
console.log("%cSelect Navigation (Internal)%cv1.8.0", "background: #2d2d2d; color: #fff; padding: 6px 10px; border-radius: 16px 0 0 16px; font-weight: 600;" , "background: #6e00ee; color: #fff; padding: 6px 10px; border-radius: 0 16px 16px 0; font-weight: 600;");
var selectInternalClass = ".select-internal";
var selectInternalLabelClass = ".select-internal__label";
var selectInternalSelectClass = ".select-internal__select";
var selectInternalOptionClass = ".select-internal__select option";
var selectInternalContentClass = ".select-internal__content";
var selectInternalDataCustomAriaLive = "data-aria-live";
var selectInternal = document.querySelectorAll(selectInternalClass);
var selectInternalLabel = document.querySelectorAll(selectInternalLabelClass);
var selectInternalSelect = document.querySelectorAll(selectInternalSelectClass);
var selectInternalState = "active";
var selectInternalContentList = [];
// On page load
selectInternal.forEach(function(component) {
// Check if "dynamic" Jump Menu is in use.
if (component.hasAttribute("data-dynamic")) {
var selectInternalContent = component.querySelectorAll(selectInternalContentClass);
var selectInternalContentNth = component.querySelectorAll(selectInternalContentClass + ":nth-of-type(n + 2)");
selectInternalContentNth.forEach(function(content) {
content.setAttribute("hidden", "");
});
selectInternalContent.forEach(function(content, i) {
var count = i + 1;
// If custom ID present
var contentID = content.hasAttribute("data-id") ? content.getAttribute("data-id"): "content-" + count;
content.setAttribute("id", contentID);
// Create option element
var option = document.createElement("option");
option.setAttribute("value", "#" + contentID);
option.textContent = content.getAttribute("data-label");
// Append each dynamic option.
component.querySelector("select").appendChild(option);
});
}
});
var selectInternalOption = document.querySelectorAll(selectInternalOptionClass);
selectInternalLabel.forEach(function(label, e) {
// Apply "for" attribute to each label.
label.setAttribute("for", "select-internal-" + (e + 1));
});
selectInternalSelect.forEach(function(select, e) {
// Apply "id" to each select.
select.setAttribute("id", "select-internal-" + (e + 1));
});
// Get all Job Menu options on page and push to array.
selectInternalOption.forEach(function(option) {
selectInternalContentList.push(option.getAttribute("value"));
});
function selectInternalSelectedState() {
var selectInternalHash = location.hash || selectInternalContentList[0];
if (!selectInternalHash) {
return;
}
var selectInternalFragment = selectInternalHash.slice(1);
// Check array against hash
if (selectInternalContentList.includes(selectInternalHash)) {
// If hash matches one of the array selections, load the selected content in hash
var selectInternalSelected = document.getElementById(selectInternalFragment);
var selectInternalContent = selectInternalSelected.closest(selectInternalClass).querySelectorAll(selectInternalContentClass);
selectInternalContent.forEach(function(content) {
content.setAttribute("hidden", "");
});
selectInternalSelected.removeAttribute("hidden");
selectInternalOption.forEach(function(option) {
var optionValue = option.getAttribute("value");
if (location.hash === optionValue) {
option.setAttribute("selected", "");
option.closest(selectInternalClass).classList.add(selectInternalState);
} else {
option.removeAttribute("selected");
}
});
// Update select dropdown
var select = document.querySelector(selectInternalClass + " select");
if (select) {
select.value = selectInternalHash;
}
}
}
selectInternalSelectedState();
// Hash change event listener
window.addEventListener("hashchange", function() {
selectInternalSelectedState();
// When link is pressed, place programatic focus on selected content. This is useful if links are elsewhere on the page.
// If this causes issues elsewhere on page when haschange is fired, let me know.
var selectedContent = document.querySelector(selectInternalContentClass + ":not([hidden])");
var selectedContentID = selectedContent.getAttribute("id");
var URLHash = location.hash.slice(1);
if(URLHash === selectedContentID) {
selectedContent.setAttribute("tabindex", "-1");
selectedContent.focus();
}
});
selectInternalSelect.forEach(function(select) {
select.addEventListener("change", function() {
var selectInternalParent = this.closest(selectInternalClass);
var selectInternalContent = selectInternalParent.querySelectorAll(selectInternalContentClass);
// Send message to screen reader.
var selectInternalAnnounce = selectInternalParent.querySelector("div[aria-live]");
if(!selectInternalParent.hasAttribute(selectInternalDataCustomAriaLive)){
selectInternalAnnounce.textContent = "Selected Content: " + this.options[this.selectedIndex].text; // TODO: Tokenize for i18n.
}
// Update hash in URL
if (this.value === "") {
var urlWithoutHash = window.location.href.split("#")[0];
history.replaceState(null, null, urlWithoutHash);
selectInternalAnnounce.textContent = "";
} else {
history.replaceState(null, null, this.value);
}
selectInternalContent.forEach(function(content) {
content.setAttribute("hidden", "");
});
var selectInternalContentSelected = location.hash.slice(1);
document.getElementById(selectInternalContentSelected).removeAttribute("hidden");
// Set selected jump menu to active.
selectInternal.forEach(function(menu) {
menu.classList.remove(selectInternalState);
});
selectInternalParent.classList.add(selectInternalState);
});
});
// Fix for some browsers not resetting the select index on page unload.
window.addEventListener("beforeunload", function() {
selectInternal.forEach(function(menu) {
if (!menu.classList.contains(selectInternalState)) {
menu.querySelector("select").selectedIndex = 0;
}
});
});
})();Select with Placeholder Anchor (Select with Placeholder)
CEO
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
Minister of Silly Walks
Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
Director, Global UI & UX Delivery
Pellentesque habitant et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante.
- Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
- Aliquam tincidunt mauris eu risus.
- Vestibulum auctor dapibus neque.
<div class="select-internal">
<nav aria-label="Preferred Job Position" class="select-internal__nav">
<label class="select-internal__label">Select your preferred job position</label>
<select class="select-internal__select">
<option value>Please Select</option>
<option value="#ceo">CEO</option>
<option value="#silly-walks">Minister of Silly Walks</option>
<option value="#director-ui-ux">Director, Global UI & UX Delivery</option>
</select>
<div class="visually-hidden" aria-live="polite"></div>
</nav>
<div class="select-internal__content" hidden id="ceo">
<h2>CEO</h2>
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, <a href="#!">tempor sit amet</a>, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
</div>
<div class="select-internal__content" hidden id="silly-walks">
<h2>Minister of Silly Walks</h2>
<p>Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
</div>
<div class="select-internal__content" hidden id="director-ui-ux">
<h2>Director, Global UI & UX Delivery</h2>
<p>Pellentesque habitant et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante.</p>
<ul>
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
<li>Aliquam tincidunt mauris eu risus.</li>
<li>Vestibulum auctor dapibus neque.</li>
</ul>
</div>
</div>/*!
Radancy Component Library: Select Navigation (Internal)
Contributor(s):
Michael "Spell" Spellacy
Dependencies: Sass
*/
.select-internal {
&__nav {
background-color: #eee;
border-radius: .5em;
display: grid;
gap: .5em;
max-inline-size: calc(420rem / 16);
padding: 1em;
}
&__label {
font-weight: bold;
margin: 0;
}
&__select {
background-color: #FFF;
border: 1px #ccc solid;
font-size: inherit;
padding: .5em;
inline-size: 100%;
}
&__content {
margin-block-start: 2em;
&:target {
scroll-margin-top: calc(190em / 16);
}
}
// Custom Select
&[data-custom-select] {
--select-primary-color: #6F00EF;
--select-border-radius: calc(5rem / 16);
.select-internal__select, ::picker(select) {
appearance: base-select;
line-height: normal;
}
.select-internal__select {
border-radius: var(--select-border-radius);
&:focus-visible {
outline: calc(2rem / 16) var(--select-primary-color) solid;
outline-offset: calc(2rem / 16);
}
&::picker-icon {
color: var(--select-primary-color);
transition: .4s rotate;
}
&:open::picker-icon {
rotate: 180deg;
}
optgroup {
option {
margin-inline-start: 1rem;
}
}
legend {
color: var(--select-primary-color);
margin-block: 1rem;
}
option {
border-radius: var(--select-border-radius);
margin-block-end: calc(8rem / 16);
padding: calc(8rem / 16) calc(8rem / 16) calc(8rem / 16) 1rem;
&::checkmark {
border-radius: 100vw;
border: calc(2rem / 16) #fff solid;
color: #fff;
font-weight: bold;
margin-inline-start: auto;
order: 1;
padding: calc(3rem / 16) calc(8rem / 16);
}
&[value=""] {
background-color: #eee;
&:not(:hover):not(:focus) {
&::checkmark {
border-color: #000;
color: #000;
}
}
}
&:focus, &:hover {
outline: 0;
color: #fff;
background-color: var(--select-primary-color);
}
}
}
// This is the select dropdown
::picker(select) {
border-radius: var(--select-border-radius);
border: calc(1rem / 16) #666 solid;
box-shadow: 0 calc(4rem / 16) calc(16rem / 16) rgb(0 0 0 / .8);
margin: 1rem 1rem 0 0;
padding: 1rem;
scrollbar-color: var(--select-primary-color) transparent;
scrollbar-width: thin;
}
}
}/*!
Radancy Component Library: Select Navigation (Internal)
Contributor(s):
Michael "Spell" Spellacy
*/
(function() {
"use strict";
// Display which component is in use via console:
console.log("%cSelect Navigation (Internal)%cv1.8.0", "background: #2d2d2d; color: #fff; padding: 6px 10px; border-radius: 16px 0 0 16px; font-weight: 600;" , "background: #6e00ee; color: #fff; padding: 6px 10px; border-radius: 0 16px 16px 0; font-weight: 600;");
var selectInternalClass = ".select-internal";
var selectInternalLabelClass = ".select-internal__label";
var selectInternalSelectClass = ".select-internal__select";
var selectInternalOptionClass = ".select-internal__select option";
var selectInternalContentClass = ".select-internal__content";
var selectInternalDataCustomAriaLive = "data-aria-live";
var selectInternal = document.querySelectorAll(selectInternalClass);
var selectInternalLabel = document.querySelectorAll(selectInternalLabelClass);
var selectInternalSelect = document.querySelectorAll(selectInternalSelectClass);
var selectInternalState = "active";
var selectInternalContentList = [];
// On page load
selectInternal.forEach(function(component) {
// Check if "dynamic" Jump Menu is in use.
if (component.hasAttribute("data-dynamic")) {
var selectInternalContent = component.querySelectorAll(selectInternalContentClass);
var selectInternalContentNth = component.querySelectorAll(selectInternalContentClass + ":nth-of-type(n + 2)");
selectInternalContentNth.forEach(function(content) {
content.setAttribute("hidden", "");
});
selectInternalContent.forEach(function(content, i) {
var count = i + 1;
// If custom ID present
var contentID = content.hasAttribute("data-id") ? content.getAttribute("data-id"): "content-" + count;
content.setAttribute("id", contentID);
// Create option element
var option = document.createElement("option");
option.setAttribute("value", "#" + contentID);
option.textContent = content.getAttribute("data-label");
// Append each dynamic option.
component.querySelector("select").appendChild(option);
});
}
});
var selectInternalOption = document.querySelectorAll(selectInternalOptionClass);
selectInternalLabel.forEach(function(label, e) {
// Apply "for" attribute to each label.
label.setAttribute("for", "select-internal-" + (e + 1));
});
selectInternalSelect.forEach(function(select, e) {
// Apply "id" to each select.
select.setAttribute("id", "select-internal-" + (e + 1));
});
// Get all Job Menu options on page and push to array.
selectInternalOption.forEach(function(option) {
selectInternalContentList.push(option.getAttribute("value"));
});
function selectInternalSelectedState() {
var selectInternalHash = location.hash || selectInternalContentList[0];
if (!selectInternalHash) {
return;
}
var selectInternalFragment = selectInternalHash.slice(1);
// Check array against hash
if (selectInternalContentList.includes(selectInternalHash)) {
// If hash matches one of the array selections, load the selected content in hash
var selectInternalSelected = document.getElementById(selectInternalFragment);
var selectInternalContent = selectInternalSelected.closest(selectInternalClass).querySelectorAll(selectInternalContentClass);
selectInternalContent.forEach(function(content) {
content.setAttribute("hidden", "");
});
selectInternalSelected.removeAttribute("hidden");
selectInternalOption.forEach(function(option) {
var optionValue = option.getAttribute("value");
if (location.hash === optionValue) {
option.setAttribute("selected", "");
option.closest(selectInternalClass).classList.add(selectInternalState);
} else {
option.removeAttribute("selected");
}
});
// Update select dropdown
var select = document.querySelector(selectInternalClass + " select");
if (select) {
select.value = selectInternalHash;
}
}
}
selectInternalSelectedState();
// Hash change event listener
window.addEventListener("hashchange", function() {
selectInternalSelectedState();
// When link is pressed, place programatic focus on selected content. This is useful if links are elsewhere on the page.
// If this causes issues elsewhere on page when haschange is fired, let me know.
var selectedContent = document.querySelector(selectInternalContentClass + ":not([hidden])");
var selectedContentID = selectedContent.getAttribute("id");
var URLHash = location.hash.slice(1);
if(URLHash === selectedContentID) {
selectedContent.setAttribute("tabindex", "-1");
selectedContent.focus();
}
});
selectInternalSelect.forEach(function(select) {
select.addEventListener("change", function() {
var selectInternalParent = this.closest(selectInternalClass);
var selectInternalContent = selectInternalParent.querySelectorAll(selectInternalContentClass);
// Send message to screen reader.
var selectInternalAnnounce = selectInternalParent.querySelector("div[aria-live]");
if(!selectInternalParent.hasAttribute(selectInternalDataCustomAriaLive)){
selectInternalAnnounce.textContent = "Selected Content: " + this.options[this.selectedIndex].text; // TODO: Tokenize for i18n.
}
// Update hash in URL
if (this.value === "") {
var urlWithoutHash = window.location.href.split("#")[0];
history.replaceState(null, null, urlWithoutHash);
selectInternalAnnounce.textContent = "";
} else {
history.replaceState(null, null, this.value);
}
selectInternalContent.forEach(function(content) {
content.setAttribute("hidden", "");
});
var selectInternalContentSelected = location.hash.slice(1);
document.getElementById(selectInternalContentSelected).removeAttribute("hidden");
// Set selected jump menu to active.
selectInternal.forEach(function(menu) {
menu.classList.remove(selectInternalState);
});
selectInternalParent.classList.add(selectInternalState);
});
});
// Fix for some browsers not resetting the select index on page unload.
window.addEventListener("beforeunload", function() {
selectInternal.forEach(function(menu) {
if (!menu.classList.contains(selectInternalState)) {
menu.querySelector("select").selectedIndex = 0;
}
});
});
})();Select with Option Group Anchor (Select with Option Group)
Lucid Air
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
Nissan Leaf
Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
BMW 7 Series
Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
Ferrari Roma
Pellentesque habitant et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante.
- Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
- Aliquam tincidunt mauris eu risus.
- Vestibulum auctor dapibus neque.
<div class="select-internal">
<nav aria-label="Fancy Cars" class="select-internal__nav">
<label class="select-internal__label">Select your vehicle</label>
<select class="select-internal__select">
<option value>Please Select</option>
<optgroup label="Electric Cars">
<option disabled value="#tesla-model-s">Tesla Model S</option>
<option value="#lucid-air">Lucid Air</option>
<option value="#nissan-leaf">Nissan Leaf</option>
</optgroup>
<optgroup label="Luxury Cars">
<option value="#bmw-7series">BMW 7 Series</option>
</optgroup>
<optgroup label="Sports Cars">
<option value="#ferrari-roma">Ferrari Roma</option>
</optgroup>
</select>
<div class="visually-hidden" aria-live="polite"></div>
</nav>
<div class="select-internal__content" hidden id="lucid-air">
<h2>Lucid Air</h2>
<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, <a href="#!">tempor sit amet</a>, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
</div>
<div class="select-internal__content" hidden id="nissan-leaf">
<h2>Nissan Leaf</h2>
<p>Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
</div>
<div class="select-internal__content" hidden id="bmw-7series">
<h2>BMW 7 Series</h2>
<p>Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
</div>
<div class="select-internal__content" hidden id="ferrari-roma">
<h2>Ferrari Roma</h2>
<p>Pellentesque habitant et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante.</p>
<ul>
<li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
<li>Aliquam tincidunt mauris eu risus.</li>
<li>Vestibulum auctor dapibus neque.</li>
</ul>
</div>
</div>/*!
Radancy Component Library: Select Navigation (Internal)
Contributor(s):
Michael "Spell" Spellacy
Dependencies: Sass
*/
.select-internal {
&__nav {
background-color: #eee;
border-radius: .5em;
display: grid;
gap: .5em;
max-inline-size: calc(420rem / 16);
padding: 1em;
}
&__label {
font-weight: bold;
margin: 0;
}
&__select {
background-color: #FFF;
border: 1px #ccc solid;
font-size: inherit;
padding: .5em;
inline-size: 100%;
}
&__content {
margin-block-start: 2em;
&:target {
scroll-margin-top: calc(190em / 16);
}
}
// Custom Select
&[data-custom-select] {
--select-primary-color: #6F00EF;
--select-border-radius: calc(5rem / 16);
.select-internal__select, ::picker(select) {
appearance: base-select;
line-height: normal;
}
.select-internal__select {
border-radius: var(--select-border-radius);
&:focus-visible {
outline: calc(2rem / 16) var(--select-primary-color) solid;
outline-offset: calc(2rem / 16);
}
&::picker-icon {
color: var(--select-primary-color);
transition: .4s rotate;
}
&:open::picker-icon {
rotate: 180deg;
}
optgroup {
option {
margin-inline-start: 1rem;
}
}
legend {
color: var(--select-primary-color);
margin-block: 1rem;
}
option {
border-radius: var(--select-border-radius);
margin-block-end: calc(8rem / 16);
padding: calc(8rem / 16) calc(8rem / 16) calc(8rem / 16) 1rem;
&::checkmark {
border-radius: 100vw;
border: calc(2rem / 16) #fff solid;
color: #fff;
font-weight: bold;
margin-inline-start: auto;
order: 1;
padding: calc(3rem / 16) calc(8rem / 16);
}
&[value=""] {
background-color: #eee;
&:not(:hover):not(:focus) {
&::checkmark {
border-color: #000;
color: #000;
}
}
}
&:focus, &:hover {
outline: 0;
color: #fff;
background-color: var(--select-primary-color);
}
}
}
// This is the select dropdown
::picker(select) {
border-radius: var(--select-border-radius);
border: calc(1rem / 16) #666 solid;
box-shadow: 0 calc(4rem / 16) calc(16rem / 16) rgb(0 0 0 / .8);
margin: 1rem 1rem 0 0;
padding: 1rem;
scrollbar-color: var(--select-primary-color) transparent;
scrollbar-width: thin;
}
}
}/*!
Radancy Component Library: Select Navigation (Internal)
Contributor(s):
Michael "Spell" Spellacy
*/
(function() {
"use strict";
// Display which component is in use via console:
console.log("%cSelect Navigation (Internal)%cv1.8.0", "background: #2d2d2d; color: #fff; padding: 6px 10px; border-radius: 16px 0 0 16px; font-weight: 600;" , "background: #6e00ee; color: #fff; padding: 6px 10px; border-radius: 0 16px 16px 0; font-weight: 600;");
var selectInternalClass = ".select-internal";
var selectInternalLabelClass = ".select-internal__label";
var selectInternalSelectClass = ".select-internal__select";
var selectInternalOptionClass = ".select-internal__select option";
var selectInternalContentClass = ".select-internal__content";
var selectInternalDataCustomAriaLive = "data-aria-live";
var selectInternal = document.querySelectorAll(selectInternalClass);
var selectInternalLabel = document.querySelectorAll(selectInternalLabelClass);
var selectInternalSelect = document.querySelectorAll(selectInternalSelectClass);
var selectInternalState = "active";
var selectInternalContentList = [];
// On page load
selectInternal.forEach(function(component) {
// Check if "dynamic" Jump Menu is in use.
if (component.hasAttribute("data-dynamic")) {
var selectInternalContent = component.querySelectorAll(selectInternalContentClass);
var selectInternalContentNth = component.querySelectorAll(selectInternalContentClass + ":nth-of-type(n + 2)");
selectInternalContentNth.forEach(function(content) {
content.setAttribute("hidden", "");
});
selectInternalContent.forEach(function(content, i) {
var count = i + 1;
// If custom ID present
var contentID = content.hasAttribute("data-id") ? content.getAttribute("data-id"): "content-" + count;
content.setAttribute("id", contentID);
// Create option element
var option = document.createElement("option");
option.setAttribute("value", "#" + contentID);
option.textContent = content.getAttribute("data-label");
// Append each dynamic option.
component.querySelector("select").appendChild(option);
});
}
});
var selectInternalOption = document.querySelectorAll(selectInternalOptionClass);
selectInternalLabel.forEach(function(label, e) {
// Apply "for" attribute to each label.
label.setAttribute("for", "select-internal-" + (e + 1));
});
selectInternalSelect.forEach(function(select, e) {
// Apply "id" to each select.
select.setAttribute("id", "select-internal-" + (e + 1));
});
// Get all Job Menu options on page and push to array.
selectInternalOption.forEach(function(option) {
selectInternalContentList.push(option.getAttribute("value"));
});
function selectInternalSelectedState() {
var selectInternalHash = location.hash || selectInternalContentList[0];
if (!selectInternalHash) {
return;
}
var selectInternalFragment = selectInternalHash.slice(1);
// Check array against hash
if (selectInternalContentList.includes(selectInternalHash)) {
// If hash matches one of the array selections, load the selected content in hash
var selectInternalSelected = document.getElementById(selectInternalFragment);
var selectInternalContent = selectInternalSelected.closest(selectInternalClass).querySelectorAll(selectInternalContentClass);
selectInternalContent.forEach(function(content) {
content.setAttribute("hidden", "");
});
selectInternalSelected.removeAttribute("hidden");
selectInternalOption.forEach(function(option) {
var optionValue = option.getAttribute("value");
if (location.hash === optionValue) {
option.setAttribute("selected", "");
option.closest(selectInternalClass).classList.add(selectInternalState);
} else {
option.removeAttribute("selected");
}
});
// Update select dropdown
var select = document.querySelector(selectInternalClass + " select");
if (select) {
select.value = selectInternalHash;
}
}
}
selectInternalSelectedState();
// Hash change event listener
window.addEventListener("hashchange", function() {
selectInternalSelectedState();
// When link is pressed, place programatic focus on selected content. This is useful if links are elsewhere on the page.
// If this causes issues elsewhere on page when haschange is fired, let me know.
var selectedContent = document.querySelector(selectInternalContentClass + ":not([hidden])");
var selectedContentID = selectedContent.getAttribute("id");
var URLHash = location.hash.slice(1);
if(URLHash === selectedContentID) {
selectedContent.setAttribute("tabindex", "-1");
selectedContent.focus();
}
});
selectInternalSelect.forEach(function(select) {
select.addEventListener("change", function() {
var selectInternalParent = this.closest(selectInternalClass);
var selectInternalContent = selectInternalParent.querySelectorAll(selectInternalContentClass);
// Send message to screen reader.
var selectInternalAnnounce = selectInternalParent.querySelector("div[aria-live]");
if(!selectInternalParent.hasAttribute(selectInternalDataCustomAriaLive)){
selectInternalAnnounce.textContent = "Selected Content: " + this.options[this.selectedIndex].text; // TODO: Tokenize for i18n.
}
// Update hash in URL
if (this.value === "") {
var urlWithoutHash = window.location.href.split("#")[0];
history.replaceState(null, null, urlWithoutHash);
selectInternalAnnounce.textContent = "";
} else {
history.replaceState(null, null, this.value);
}
selectInternalContent.forEach(function(content) {
content.setAttribute("hidden", "");
});
var selectInternalContentSelected = location.hash.slice(1);
document.getElementById(selectInternalContentSelected).removeAttribute("hidden");
// Set selected jump menu to active.
selectInternal.forEach(function(menu) {
menu.classList.remove(selectInternalState);
});
selectInternalParent.classList.add(selectInternalState);
});
});
// Fix for some browsers not resetting the select index on page unload.
window.addEventListener("beforeunload", function() {
selectInternal.forEach(function(menu) {
if (!menu.classList.contains(selectInternalState)) {
menu.querySelector("select").selectedIndex = 0;
}
});
});
})();Select with Option Group (Customized Select Element) Anchor (Select with Option Group (Customized Select Element))
Mad Max: Fury Road
A high-octane post-apocalyptic action film filled with relentless chases, practical effects, and minimal dialogue, centered on survival in a desert wasteland.
John Wick
A sleek, stylized action thriller following a retired hitman seeking vengeance, known for its precise choreography and world-building within an underground assassin society.
The Dark Knight
A gritty superhero crime drama exploring chaos and morality, featuring an iconic performance of the Joker and complex themes of justice and sacrifice.
Superbad
A coming-of-age comedy that follows two friends navigating one wild night before graduation, packed with awkward humor and memorable characters.
Step Brothers
A ridiculous and irreverent comedy about two grown men forced to live together as siblings, leading to absurd conflicts and unexpected bonding.
The Shawshank Redemption
A powerful drama about hope and resilience, following a man wrongfully imprisoned and his enduring friendship inside a harsh prison system.
Forrest Gump
A heartfelt drama chronicling the extraordinary life of an ordinary man, weaving through major historical events with sincerity and charm.
Interstellar
A visually stunning science fiction epic exploring space travel, time dilation, and human survival as a team ventures beyond our galaxy.
Blade Runner 2049
A contemplative sci-fi sequel that blends stunning visuals with philosophical questions about identity, memory, and what it means to be human.
Experimental: Experimental examples or components may require additional work, further testing, and may not be fully supported or accessible. They should be carefully evaluated before being used in a production environment.
<div class="select-internal" data-custom-select>
<nav aria-label="Movies" class="select-internal__nav">
<label class="select-internal__label">Select your movie</label>
<select class="select-internal__select">
<button>
<selectedcontent></selectedcontent>
</button>
<option value>Please Select</option>
<optgroup label="Action">
<legend>Action</legend>
<div>
<option value="#mad-max-fury-road">Mad Max: Fury Road</option>
<option value="#john-wick">John Wick</option>
<option value="#the-dark-knight">The Dark Knight</option>
</div>
</optgroup>
<optgroup label="Comedy">
<legend>Comedy</legend>
<div>
<option value="#superbad">Superbad</option>
<option value="#step-brothers">Step Brothers</option>
</div>
</optgroup>
<optgroup label="Drama">
<legend>Drama</legend>
<div>
<option value="#shawshank-redemption">The Shawshank Redemption</option>
<option value="#forrest-gump">Forrest Gump</option>
</div>
</optgroup>
<optgroup label="Science Fiction">
<legend>Science Fiction</legend>
<div>
<option value="#interstellar">Interstellar</option>
<option value="#blade-runner-2049">Blade Runner 2049</option>
</div>
</optgroup>
</select>
<div class="visually-hidden" aria-live="polite"></div>
</nav>
<div class="select-internal__content" hidden id="mad-max-fury-road">
<h2>Mad Max: Fury Road</h2>
<p>A high-octane post-apocalyptic action film filled with relentless chases, practical effects, and minimal dialogue, centered on survival in a desert wasteland.</p>
</div>
<div class="select-internal__content" hidden id="john-wick">
<h2>John Wick</h2>
<p>A sleek, stylized action thriller following a retired hitman seeking vengeance, known for its precise choreography and world-building within an underground assassin society.</p>
</div>
<div class="select-internal__content" hidden id="the-dark-knight">
<h2>The Dark Knight</h2>
<p>A gritty superhero crime drama exploring chaos and morality, featuring an iconic performance of the Joker and complex themes of justice and sacrifice.</p>
</div>
<div class="select-internal__content" hidden id="superbad">
<h2>Superbad</h2>
<p>A coming-of-age comedy that follows two friends navigating one wild night before graduation, packed with awkward humor and memorable characters.</p>
</div>
<div class="select-internal__content" hidden id="step-brothers">
<h2>Step Brothers</h2>
<p>A ridiculous and irreverent comedy about two grown men forced to live together as siblings, leading to absurd conflicts and unexpected bonding.</p>
</div>
<div class="select-internal__content" hidden id="shawshank-redemption">
<h2>The Shawshank Redemption</h2>
<p>A powerful drama about hope and resilience, following a man wrongfully imprisoned and his enduring friendship inside a harsh prison system.</p>
</div>
<div class="select-internal__content" hidden id="forrest-gump">
<h2>Forrest Gump</h2>
<p>A heartfelt drama chronicling the extraordinary life of an ordinary man, weaving through major historical events with sincerity and charm.</p>
</div>
<div class="select-internal__content" hidden id="interstellar">
<h2>Interstellar</h2>
<p>A visually stunning science fiction epic exploring space travel, time dilation, and human survival as a team ventures beyond our galaxy.</p>
</div>
<div class="select-internal__content" hidden id="blade-runner-2049">
<h2>Blade Runner 2049</h2>
<p>A contemplative sci-fi sequel that blends stunning visuals with philosophical questions about identity, memory, and what it means to be human.</p>
</div>
</div>/*!
Radancy Component Library: Select Navigation (Internal)
Contributor(s):
Michael "Spell" Spellacy
Dependencies: Sass
*/
.select-internal {
&__nav {
background-color: #eee;
border-radius: .5em;
display: grid;
gap: .5em;
max-inline-size: calc(420rem / 16);
padding: 1em;
}
&__label {
font-weight: bold;
margin: 0;
}
&__select {
background-color: #FFF;
border: 1px #ccc solid;
font-size: inherit;
padding: .5em;
inline-size: 100%;
}
&__content {
margin-block-start: 2em;
&:target {
scroll-margin-top: calc(190em / 16);
}
}
// Custom Select
&[data-custom-select] {
--select-primary-color: #6F00EF;
--select-border-radius: calc(5rem / 16);
.select-internal__select, ::picker(select) {
appearance: base-select;
line-height: normal;
}
.select-internal__select {
border-radius: var(--select-border-radius);
&:focus-visible {
outline: calc(2rem / 16) var(--select-primary-color) solid;
outline-offset: calc(2rem / 16);
}
&::picker-icon {
color: var(--select-primary-color);
transition: .4s rotate;
}
&:open::picker-icon {
rotate: 180deg;
}
optgroup {
option {
margin-inline-start: 1rem;
}
}
legend {
color: var(--select-primary-color);
margin-block: 1rem;
}
option {
border-radius: var(--select-border-radius);
margin-block-end: calc(8rem / 16);
padding: calc(8rem / 16) calc(8rem / 16) calc(8rem / 16) 1rem;
&::checkmark {
border-radius: 100vw;
border: calc(2rem / 16) #fff solid;
color: #fff;
font-weight: bold;
margin-inline-start: auto;
order: 1;
padding: calc(3rem / 16) calc(8rem / 16);
}
&[value=""] {
background-color: #eee;
&:not(:hover):not(:focus) {
&::checkmark {
border-color: #000;
color: #000;
}
}
}
&:focus, &:hover {
outline: 0;
color: #fff;
background-color: var(--select-primary-color);
}
}
}
// This is the select dropdown
::picker(select) {
border-radius: var(--select-border-radius);
border: calc(1rem / 16) #666 solid;
box-shadow: 0 calc(4rem / 16) calc(16rem / 16) rgb(0 0 0 / .8);
margin: 1rem 1rem 0 0;
padding: 1rem;
scrollbar-color: var(--select-primary-color) transparent;
scrollbar-width: thin;
}
}
}/*!
Radancy Component Library: Select Navigation (Internal)
Contributor(s):
Michael "Spell" Spellacy
*/
(function() {
"use strict";
// Display which component is in use via console:
console.log("%cSelect Navigation (Internal)%cv1.8.0", "background: #2d2d2d; color: #fff; padding: 6px 10px; border-radius: 16px 0 0 16px; font-weight: 600;" , "background: #6e00ee; color: #fff; padding: 6px 10px; border-radius: 0 16px 16px 0; font-weight: 600;");
var selectInternalClass = ".select-internal";
var selectInternalLabelClass = ".select-internal__label";
var selectInternalSelectClass = ".select-internal__select";
var selectInternalOptionClass = ".select-internal__select option";
var selectInternalContentClass = ".select-internal__content";
var selectInternalDataCustomAriaLive = "data-aria-live";
var selectInternal = document.querySelectorAll(selectInternalClass);
var selectInternalLabel = document.querySelectorAll(selectInternalLabelClass);
var selectInternalSelect = document.querySelectorAll(selectInternalSelectClass);
var selectInternalState = "active";
var selectInternalContentList = [];
// On page load
selectInternal.forEach(function(component) {
// Check if "dynamic" Jump Menu is in use.
if (component.hasAttribute("data-dynamic")) {
var selectInternalContent = component.querySelectorAll(selectInternalContentClass);
var selectInternalContentNth = component.querySelectorAll(selectInternalContentClass + ":nth-of-type(n + 2)");
selectInternalContentNth.forEach(function(content) {
content.setAttribute("hidden", "");
});
selectInternalContent.forEach(function(content, i) {
var count = i + 1;
// If custom ID present
var contentID = content.hasAttribute("data-id") ? content.getAttribute("data-id"): "content-" + count;
content.setAttribute("id", contentID);
// Create option element
var option = document.createElement("option");
option.setAttribute("value", "#" + contentID);
option.textContent = content.getAttribute("data-label");
// Append each dynamic option.
component.querySelector("select").appendChild(option);
});
}
});
var selectInternalOption = document.querySelectorAll(selectInternalOptionClass);
selectInternalLabel.forEach(function(label, e) {
// Apply "for" attribute to each label.
label.setAttribute("for", "select-internal-" + (e + 1));
});
selectInternalSelect.forEach(function(select, e) {
// Apply "id" to each select.
select.setAttribute("id", "select-internal-" + (e + 1));
});
// Get all Job Menu options on page and push to array.
selectInternalOption.forEach(function(option) {
selectInternalContentList.push(option.getAttribute("value"));
});
function selectInternalSelectedState() {
var selectInternalHash = location.hash || selectInternalContentList[0];
if (!selectInternalHash) {
return;
}
var selectInternalFragment = selectInternalHash.slice(1);
// Check array against hash
if (selectInternalContentList.includes(selectInternalHash)) {
// If hash matches one of the array selections, load the selected content in hash
var selectInternalSelected = document.getElementById(selectInternalFragment);
var selectInternalContent = selectInternalSelected.closest(selectInternalClass).querySelectorAll(selectInternalContentClass);
selectInternalContent.forEach(function(content) {
content.setAttribute("hidden", "");
});
selectInternalSelected.removeAttribute("hidden");
selectInternalOption.forEach(function(option) {
var optionValue = option.getAttribute("value");
if (location.hash === optionValue) {
option.setAttribute("selected", "");
option.closest(selectInternalClass).classList.add(selectInternalState);
} else {
option.removeAttribute("selected");
}
});
// Update select dropdown
var select = document.querySelector(selectInternalClass + " select");
if (select) {
select.value = selectInternalHash;
}
}
}
selectInternalSelectedState();
// Hash change event listener
window.addEventListener("hashchange", function() {
selectInternalSelectedState();
// When link is pressed, place programatic focus on selected content. This is useful if links are elsewhere on the page.
// If this causes issues elsewhere on page when haschange is fired, let me know.
var selectedContent = document.querySelector(selectInternalContentClass + ":not([hidden])");
var selectedContentID = selectedContent.getAttribute("id");
var URLHash = location.hash.slice(1);
if(URLHash === selectedContentID) {
selectedContent.setAttribute("tabindex", "-1");
selectedContent.focus();
}
});
selectInternalSelect.forEach(function(select) {
select.addEventListener("change", function() {
var selectInternalParent = this.closest(selectInternalClass);
var selectInternalContent = selectInternalParent.querySelectorAll(selectInternalContentClass);
// Send message to screen reader.
var selectInternalAnnounce = selectInternalParent.querySelector("div[aria-live]");
if(!selectInternalParent.hasAttribute(selectInternalDataCustomAriaLive)){
selectInternalAnnounce.textContent = "Selected Content: " + this.options[this.selectedIndex].text; // TODO: Tokenize for i18n.
}
// Update hash in URL
if (this.value === "") {
var urlWithoutHash = window.location.href.split("#")[0];
history.replaceState(null, null, urlWithoutHash);
selectInternalAnnounce.textContent = "";
} else {
history.replaceState(null, null, this.value);
}
selectInternalContent.forEach(function(content) {
content.setAttribute("hidden", "");
});
var selectInternalContentSelected = location.hash.slice(1);
document.getElementById(selectInternalContentSelected).removeAttribute("hidden");
// Set selected jump menu to active.
selectInternal.forEach(function(menu) {
menu.classList.remove(selectInternalState);
});
selectInternalParent.classList.add(selectInternalState);
});
});
// Fix for some browsers not resetting the select index on page unload.
window.addEventListener("beforeunload", function() {
selectInternal.forEach(function(menu) {
if (!menu.classList.contains(selectInternalState)) {
menu.querySelector("select").selectedIndex = 0;
}
});
});
})();Properties Anchor (Properties)
Use the following properties to configure this component.
| ARIA | Applies To | Note | Description |
|---|---|---|---|
aria-label |
.select-internal__nav |
Mandatory | Used to pass a custom label to nav element. All menus must have a unique name describing them. Multiple menus on the page, should have a unique name. |
| Attribute | Applies To | Note | Description |
|---|---|---|---|
data-aria-live |
.select-internal |
Boolean, Optional | Used to suppress dynamic aria-live announcements. Here, you will be expected to wrap all of your .select-internal__content blocks with a single <div aria-live="polite"></div>. This technique should be used sparingly and only when each content area contains a minimal amount of content. |
data-custom-select |
.select-internal |
Boolean, Optional | Used to allow custom styling of the select element and it's children. See Customizable Select Elements for more details. |
data-dynamic |
.select-internal |
Boolean, Optional | Used in situations where you do not wish to hardcode the option element. The name of each option will be pulled from data-name. |
data-id |
.select-internal__content |
String, Optional | Used with data-dynamic. This will provide a custom id value to each .select-internal__content container and a custom value to each option element. Custom values will override dynamically generated content-1, content-2, etc. Each custom value must be unique. |
data-label |
.select-internal__content |
String, Mandatory | Used with data-dynamic. This will provide a custom value for any dynamically created option elements. |
| Class | Applies To | Note | Description |
|---|---|---|---|
.select-internal |
div, section |
Mandatory | Required on the parent element that wraps the menu and content. |
.select-internal__nav |
nav |
Mandatory | Required on the nav element that wraps the label and select elements. |
.select-internal__select |
select |
Mandatory | Required on the select element. |
.select-internal__content |
div |
Mandatory | Required on each element that wraps individual content. |
Release Notes Anchor (Release Notes)
Keep up to date on major changes to this component.
- Feature
- March 24, 2026: Added support for Customizable Select Elements.
- Behavior
- Select Menus should never be nested, nor is it supported.
- Behavior
- Removing the fragment from the URL is not supported. We want dynamically displayed content to be uniquely identified so that we can to link to and share it. The dynamic version of the menu will produce generic fragments (e.g., content-1, content-2, etc.).
- Behavior
<div class="visually-hidden" aria-live="polite"></div>must always be included and be accessibly hidden.- Feature
- The
forandidattributes are generated via JavaScript to accomodate multiple Jump Menus per page. There is no need to manually add these attributes.
- Feature
- Include support for the
optgroupelement in Dynamic Setup.
Report Issues
Find a bug? Want a new feature? Report it on JIRA. You're so awesome!