Disclosure v2.4.0
Reaveal or hide additional content when triggered, helping to manage the display of supplementary information.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.
Reminder: A disclosure is intended for (mostly) single-purpose use. If you need to group multiple disclosures, such as in a FAQ or similar layout, please use the Accordion component.
<button class="disclosure--btn">Learn More</button>
<div class="disclosure--content">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.</p>
</div>/*!
Radancy Component Library: Disclosure
Contributor(s):
Michael "Spell" Spellacy
Dependencies: Sass
*/
// Sass Variables
$disclosure-breakpoint: 60em;
:root {
--disclosure-arrow-size: 0.8em; // Toggle Arrow Size
--disclosure-arrow-border: calc(2rem / 16); // Toggle Arrow Border
--disclosure-base-color: #6F00EF; // Primary Color
--disclosure-color-active: #a9a9a9; // Active State
--disclosure-color-default: #d3d3d3; // Default States
--disclosure-color-interactive: #666; // Interactive State
--disclosure-color-selected: var(--disclosure-base-color); // Selected States
}
// Disclosure Button
.disclosure--btn {
background-color: var(--disclosure-color-default) ;
border: 0;
color: inherit;
cursor: pointer;
display: grid;
font-size: inherit;
grid-auto-flow: column;
line-height: normal;
padding: 1em;
position: relative;
text-align: start;
width: 100%;
// Accessibility: Focus and hover states must meet a 3:1 color ratio between background color and foreground text.
// The project designer should be providing this state. Also, never remove focus outlines! Either redesign them or
// design an alternative focus state. Learn: https://webaim.org/articles/contrast/
&:focus-visible, &:hover {
background-color: var(--disclosure-color-active);
}
&:focus-visible {
outline-offset: -5px;
}
&[aria-expanded="true"] {
background-color: var(--disclosure-color-selected);
color: #fff;
// Disclosure Arrow: State
.disclosure--arrow {
border-block-end-color: #fff;
border-inline-start-color: #fff;
transform: rotate(135deg);
translate: 0 calc(8rem/16);
}
}
}
// Disclosure Heading
.disclosure--heading {
all: unset;
display: contents;
}
// Disclosure Arrow
.disclosure--arrow {
block-size: var(--disclosure-arrow-size);
border-width: var(--disclosure-arrow-border);
border-block-color: transparent var(--disclosure-color-selected);
border-block-start-width: 0;
border-inline-color: var(--disclosure-color-selected) transparent;
border-inline-end-width: 0;
border-style: solid;
content: "";
direction: ltr;
display: block;
inline-size: var(--disclosure-arrow-size);
justify-self: end;
transform: rotate(-45deg);
}
// Disclosure Content
.disclosure--content {
background-color: var(--disclosure-color-default);
display: none;
overflow: hidden;
padding: 1em;
&[data-animation] {
@media (prefers-reduced-motion: no-preference) {
transition: display 0s, max-height 3s allow-discrete;
}
}
}
// Persistent State
.disclosure--btn, .disclosure--heading {
&[data-persistent] {
@media(min-width: $disclosure-breakpoint) {
display: none;
+ .disclosure--content {
display: block;
}
}
}
}
// Viewport Context
.disclosure--btn, .disclosure--heading {
&[data-context], &[data-disclosure-viewport] {
@media(min-width: $disclosure-breakpoint) {
padding: 0;
pointer-events: none;
visibility: hidden;
.disclosure--btn {
padding: inherit;
pointer-events: inherit;
visibility: inherit;
}
span:not([aria-hidden]) {
color: var(--disclosure-base-color);
font-weight: 700;
visibility: visible;
}
// If icon present
span[aria-hidden] {
display: none;
}
+ .disclosure--content {
background-color: transparent;
display: block;
padding: 0;
}
}
}
}
// Disclosure Event
.disclosure--btn[aria-expanded="true"] + .disclosure--content, .disclosure--heading:has(.disclosure--btn[aria-expanded="true"]) + .disclosure--content {
display: block;
&[data-animation] {
max-height: 5000px;
@starting-style {
max-height: 0;
}
}
}/*!
Radancy Component Library: Disclosure
Contributor(s):
Michael "Spell" Spellacy
*/
(() => {
"use strict";
// Display which Disclosure is in use via console:
console.log("%cDisclosure%cv2.4.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;");
// Commonly used Classes, Data Attributes, States, Strings, etc.
const disclosureButtonClass = ".disclosure--btn";
const disclosureButtons = document.querySelectorAll(disclosureButtonClass);
const disclosureArrowClassName = "disclosure--arrow";
const disclosureHeadingClass = ".disclosure--heading";
const disclosureDataDefaultOpen = "data-open";
const disclosureDataEnableAnchor = "data-enable-anchor";
const disclosureDataRemoveArrow = "data-remove-arrow";
// Add Listener and other needed attributes to disclosure button
disclosureButtons.forEach((button, index) => {
const count = index + 1;
button.setAttribute("aria-expanded", "false");
let thisButtonID, thisContentID;
if (button.hasAttribute("id")) {
// Check for custom ID on button.
thisButtonID = button.getAttribute("id");
thisContentID = `${thisButtonID}-content`;
} else {
// Else, add dynamic ID.
thisButtonID = `disclosure-btn-${count}`;
thisContentID = `disclosure-content-${count}`;
}
// Set ID and aria-controls on button.
button.setAttribute("id", thisButtonID);
button.setAttribute("aria-controls", thisContentID);
if (button.closest(disclosureHeadingClass)) {
// If button contains heading...
button.closest(disclosureHeadingClass).nextElementSibling.setAttribute("id", thisContentID);
} else {
button.nextElementSibling.setAttribute("id", thisContentID);
}
// If custom arrow not needed.
if (!button.hasAttribute(disclosureDataRemoveArrow)) {
const toggleState = document.createElement("span");
toggleState.setAttribute("aria-hidden", "true");
toggleState.classList.add(disclosureArrowClassName);
button.append(toggleState);
}
button.addEventListener("click", () => {
const isExpanded = button.getAttribute("aria-expanded") === "true";
button.setAttribute("aria-expanded", isExpanded ? "false" : "true");
if (button.hasAttribute(disclosureDataEnableAnchor)) {
history.pushState(null, null, `#${button.id}`);
}
});
// Open desired disclosure.
if (button.hasAttribute(disclosureDataDefaultOpen)) {
button.setAttribute("aria-expanded", "true");
}
});
// Open selected disclosure via URL
const url = document.location.href;
const hash = url.split("#");
const disclosureID = document.getElementById(hash[1]);
if(disclosureID) {
const disclosureTarget = document.querySelector(disclosureButtonClass + "#" + disclosureID.id);
if (disclosureTarget) {
disclosureTarget.setAttribute("aria-expanded", "true");
disclosureTarget.focus();
}
}
})();What do you mean? An African or a European swallow?
I don't know that. Aaaaaaaaagh!
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.
Reminder: A disclosure is intended for (mostly) single-purpose use. If you need to group multiple disclosures, such as in a FAQ or similar layout, please use the Accordion component.
Experimental: Please note that this example uses the new @starting-style at-rule and transition-behavior: allow-discrete; to produce animation. This technique is supported in most major browsers. If you require specific animations in non-supporting browserss, you will need to come up with a traditional implementation.
<button class="disclosure--btn">What is the airspeed velocity of an unladen swallow?</button>
<div class="disclosure--content" data-animation>
<p>What do you mean? An African or a European swallow?</p>
<p>I don't know that. Aaaaaaaaagh!</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.</p>
</div>/*!
Radancy Component Library: Disclosure
Contributor(s):
Michael "Spell" Spellacy
Dependencies: Sass
*/
// Sass Variables
$disclosure-breakpoint: 60em;
:root {
--disclosure-arrow-size: 0.8em; // Toggle Arrow Size
--disclosure-arrow-border: calc(2rem / 16); // Toggle Arrow Border
--disclosure-base-color: #6F00EF; // Primary Color
--disclosure-color-active: #a9a9a9; // Active State
--disclosure-color-default: #d3d3d3; // Default States
--disclosure-color-interactive: #666; // Interactive State
--disclosure-color-selected: var(--disclosure-base-color); // Selected States
}
// Disclosure Button
.disclosure--btn {
background-color: var(--disclosure-color-default) ;
border: 0;
color: inherit;
cursor: pointer;
display: grid;
font-size: inherit;
grid-auto-flow: column;
line-height: normal;
padding: 1em;
position: relative;
text-align: start;
width: 100%;
// Accessibility: Focus and hover states must meet a 3:1 color ratio between background color and foreground text.
// The project designer should be providing this state. Also, never remove focus outlines! Either redesign them or
// design an alternative focus state. Learn: https://webaim.org/articles/contrast/
&:focus-visible, &:hover {
background-color: var(--disclosure-color-active);
}
&:focus-visible {
outline-offset: -5px;
}
&[aria-expanded="true"] {
background-color: var(--disclosure-color-selected);
color: #fff;
// Disclosure Arrow: State
.disclosure--arrow {
border-block-end-color: #fff;
border-inline-start-color: #fff;
transform: rotate(135deg);
translate: 0 calc(8rem/16);
}
}
}
// Disclosure Heading
.disclosure--heading {
all: unset;
display: contents;
}
// Disclosure Arrow
.disclosure--arrow {
block-size: var(--disclosure-arrow-size);
border-width: var(--disclosure-arrow-border);
border-block-color: transparent var(--disclosure-color-selected);
border-block-start-width: 0;
border-inline-color: var(--disclosure-color-selected) transparent;
border-inline-end-width: 0;
border-style: solid;
content: "";
direction: ltr;
display: block;
inline-size: var(--disclosure-arrow-size);
justify-self: end;
transform: rotate(-45deg);
}
// Disclosure Content
.disclosure--content {
background-color: var(--disclosure-color-default);
display: none;
overflow: hidden;
padding: 1em;
&[data-animation] {
@media (prefers-reduced-motion: no-preference) {
transition: display 0s, max-height 3s allow-discrete;
}
}
}
// Persistent State
.disclosure--btn, .disclosure--heading {
&[data-persistent] {
@media(min-width: $disclosure-breakpoint) {
display: none;
+ .disclosure--content {
display: block;
}
}
}
}
// Viewport Context
.disclosure--btn, .disclosure--heading {
&[data-context], &[data-disclosure-viewport] {
@media(min-width: $disclosure-breakpoint) {
padding: 0;
pointer-events: none;
visibility: hidden;
.disclosure--btn {
padding: inherit;
pointer-events: inherit;
visibility: inherit;
}
span:not([aria-hidden]) {
color: var(--disclosure-base-color);
font-weight: 700;
visibility: visible;
}
// If icon present
span[aria-hidden] {
display: none;
}
+ .disclosure--content {
background-color: transparent;
display: block;
padding: 0;
}
}
}
}
// Disclosure Event
.disclosure--btn[aria-expanded="true"] + .disclosure--content, .disclosure--heading:has(.disclosure--btn[aria-expanded="true"]) + .disclosure--content {
display: block;
&[data-animation] {
max-height: 5000px;
@starting-style {
max-height: 0;
}
}
}/*!
Radancy Component Library: Disclosure
Contributor(s):
Michael "Spell" Spellacy
*/
(() => {
"use strict";
// Display which Disclosure is in use via console:
console.log("%cDisclosure%cv2.4.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;");
// Commonly used Classes, Data Attributes, States, Strings, etc.
const disclosureButtonClass = ".disclosure--btn";
const disclosureButtons = document.querySelectorAll(disclosureButtonClass);
const disclosureArrowClassName = "disclosure--arrow";
const disclosureHeadingClass = ".disclosure--heading";
const disclosureDataDefaultOpen = "data-open";
const disclosureDataEnableAnchor = "data-enable-anchor";
const disclosureDataRemoveArrow = "data-remove-arrow";
// Add Listener and other needed attributes to disclosure button
disclosureButtons.forEach((button, index) => {
const count = index + 1;
button.setAttribute("aria-expanded", "false");
let thisButtonID, thisContentID;
if (button.hasAttribute("id")) {
// Check for custom ID on button.
thisButtonID = button.getAttribute("id");
thisContentID = `${thisButtonID}-content`;
} else {
// Else, add dynamic ID.
thisButtonID = `disclosure-btn-${count}`;
thisContentID = `disclosure-content-${count}`;
}
// Set ID and aria-controls on button.
button.setAttribute("id", thisButtonID);
button.setAttribute("aria-controls", thisContentID);
if (button.closest(disclosureHeadingClass)) {
// If button contains heading...
button.closest(disclosureHeadingClass).nextElementSibling.setAttribute("id", thisContentID);
} else {
button.nextElementSibling.setAttribute("id", thisContentID);
}
// If custom arrow not needed.
if (!button.hasAttribute(disclosureDataRemoveArrow)) {
const toggleState = document.createElement("span");
toggleState.setAttribute("aria-hidden", "true");
toggleState.classList.add(disclosureArrowClassName);
button.append(toggleState);
}
button.addEventListener("click", () => {
const isExpanded = button.getAttribute("aria-expanded") === "true";
button.setAttribute("aria-expanded", isExpanded ? "false" : "true");
if (button.hasAttribute(disclosureDataEnableAnchor)) {
history.pushState(null, null, `#${button.id}`);
}
});
// Open desired disclosure.
if (button.hasAttribute(disclosureDataDefaultOpen)) {
button.setAttribute("aria-expanded", "true");
}
});
// Open selected disclosure via URL
const url = document.location.href;
const hash = url.split("#");
const disclosureID = document.getElementById(hash[1]);
if(disclosureID) {
const disclosureTarget = document.querySelector(disclosureButtonClass + "#" + disclosureID.id);
if (disclosureTarget) {
disclosureTarget.setAttribute("aria-expanded", "true");
disclosureTarget.focus();
}
}
})();Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.
Reminder: A disclosure is intended for (mostly) single-purpose use. If you need to group multiple disclosures, such as in a FAQ or similar layout, please use the Accordion component.
<button class="disclosure--btn" data-open>Learn More</button>
<div class="disclosure--content">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.</p>
</div>/*!
Radancy Component Library: Disclosure
Contributor(s):
Michael "Spell" Spellacy
Dependencies: Sass
*/
// Sass Variables
$disclosure-breakpoint: 60em;
:root {
--disclosure-arrow-size: 0.8em; // Toggle Arrow Size
--disclosure-arrow-border: calc(2rem / 16); // Toggle Arrow Border
--disclosure-base-color: #6F00EF; // Primary Color
--disclosure-color-active: #a9a9a9; // Active State
--disclosure-color-default: #d3d3d3; // Default States
--disclosure-color-interactive: #666; // Interactive State
--disclosure-color-selected: var(--disclosure-base-color); // Selected States
}
// Disclosure Button
.disclosure--btn {
background-color: var(--disclosure-color-default) ;
border: 0;
color: inherit;
cursor: pointer;
display: grid;
font-size: inherit;
grid-auto-flow: column;
line-height: normal;
padding: 1em;
position: relative;
text-align: start;
width: 100%;
// Accessibility: Focus and hover states must meet a 3:1 color ratio between background color and foreground text.
// The project designer should be providing this state. Also, never remove focus outlines! Either redesign them or
// design an alternative focus state. Learn: https://webaim.org/articles/contrast/
&:focus-visible, &:hover {
background-color: var(--disclosure-color-active);
}
&:focus-visible {
outline-offset: -5px;
}
&[aria-expanded="true"] {
background-color: var(--disclosure-color-selected);
color: #fff;
// Disclosure Arrow: State
.disclosure--arrow {
border-block-end-color: #fff;
border-inline-start-color: #fff;
transform: rotate(135deg);
translate: 0 calc(8rem/16);
}
}
}
// Disclosure Heading
.disclosure--heading {
all: unset;
display: contents;
}
// Disclosure Arrow
.disclosure--arrow {
block-size: var(--disclosure-arrow-size);
border-width: var(--disclosure-arrow-border);
border-block-color: transparent var(--disclosure-color-selected);
border-block-start-width: 0;
border-inline-color: var(--disclosure-color-selected) transparent;
border-inline-end-width: 0;
border-style: solid;
content: "";
direction: ltr;
display: block;
inline-size: var(--disclosure-arrow-size);
justify-self: end;
transform: rotate(-45deg);
}
// Disclosure Content
.disclosure--content {
background-color: var(--disclosure-color-default);
display: none;
overflow: hidden;
padding: 1em;
&[data-animation] {
@media (prefers-reduced-motion: no-preference) {
transition: display 0s, max-height 3s allow-discrete;
}
}
}
// Persistent State
.disclosure--btn, .disclosure--heading {
&[data-persistent] {
@media(min-width: $disclosure-breakpoint) {
display: none;
+ .disclosure--content {
display: block;
}
}
}
}
// Viewport Context
.disclosure--btn, .disclosure--heading {
&[data-context], &[data-disclosure-viewport] {
@media(min-width: $disclosure-breakpoint) {
padding: 0;
pointer-events: none;
visibility: hidden;
.disclosure--btn {
padding: inherit;
pointer-events: inherit;
visibility: inherit;
}
span:not([aria-hidden]) {
color: var(--disclosure-base-color);
font-weight: 700;
visibility: visible;
}
// If icon present
span[aria-hidden] {
display: none;
}
+ .disclosure--content {
background-color: transparent;
display: block;
padding: 0;
}
}
}
}
// Disclosure Event
.disclosure--btn[aria-expanded="true"] + .disclosure--content, .disclosure--heading:has(.disclosure--btn[aria-expanded="true"]) + .disclosure--content {
display: block;
&[data-animation] {
max-height: 5000px;
@starting-style {
max-height: 0;
}
}
}/*!
Radancy Component Library: Disclosure
Contributor(s):
Michael "Spell" Spellacy
*/
(() => {
"use strict";
// Display which Disclosure is in use via console:
console.log("%cDisclosure%cv2.4.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;");
// Commonly used Classes, Data Attributes, States, Strings, etc.
const disclosureButtonClass = ".disclosure--btn";
const disclosureButtons = document.querySelectorAll(disclosureButtonClass);
const disclosureArrowClassName = "disclosure--arrow";
const disclosureHeadingClass = ".disclosure--heading";
const disclosureDataDefaultOpen = "data-open";
const disclosureDataEnableAnchor = "data-enable-anchor";
const disclosureDataRemoveArrow = "data-remove-arrow";
// Add Listener and other needed attributes to disclosure button
disclosureButtons.forEach((button, index) => {
const count = index + 1;
button.setAttribute("aria-expanded", "false");
let thisButtonID, thisContentID;
if (button.hasAttribute("id")) {
// Check for custom ID on button.
thisButtonID = button.getAttribute("id");
thisContentID = `${thisButtonID}-content`;
} else {
// Else, add dynamic ID.
thisButtonID = `disclosure-btn-${count}`;
thisContentID = `disclosure-content-${count}`;
}
// Set ID and aria-controls on button.
button.setAttribute("id", thisButtonID);
button.setAttribute("aria-controls", thisContentID);
if (button.closest(disclosureHeadingClass)) {
// If button contains heading...
button.closest(disclosureHeadingClass).nextElementSibling.setAttribute("id", thisContentID);
} else {
button.nextElementSibling.setAttribute("id", thisContentID);
}
// If custom arrow not needed.
if (!button.hasAttribute(disclosureDataRemoveArrow)) {
const toggleState = document.createElement("span");
toggleState.setAttribute("aria-hidden", "true");
toggleState.classList.add(disclosureArrowClassName);
button.append(toggleState);
}
button.addEventListener("click", () => {
const isExpanded = button.getAttribute("aria-expanded") === "true";
button.setAttribute("aria-expanded", isExpanded ? "false" : "true");
if (button.hasAttribute(disclosureDataEnableAnchor)) {
history.pushState(null, null, `#${button.id}`);
}
});
// Open desired disclosure.
if (button.hasAttribute(disclosureDataDefaultOpen)) {
button.setAttribute("aria-expanded", "true");
}
});
// Open selected disclosure via URL
const url = document.location.href;
const hash = url.split("#");
const disclosureID = document.getElementById(hash[1]);
if(disclosureID) {
const disclosureTarget = document.querySelector(disclosureButtonClass + "#" + disclosureID.id);
if (disclosureTarget) {
disclosureTarget.setAttribute("aria-expanded", "true");
disclosureTarget.focus();
}
}
})();Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.
Reminder: A disclosure is intended for (mostly) single-purpose use. If you need to group multiple disclosures, such as in a FAQ or similar layout, please use the Accordion component.
<button class="disclosure--btn" data-enable-anchor>Learn More</button>
<div class="disclosure--content">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.</p>
</div>/*!
Radancy Component Library: Disclosure
Contributor(s):
Michael "Spell" Spellacy
Dependencies: Sass
*/
// Sass Variables
$disclosure-breakpoint: 60em;
:root {
--disclosure-arrow-size: 0.8em; // Toggle Arrow Size
--disclosure-arrow-border: calc(2rem / 16); // Toggle Arrow Border
--disclosure-base-color: #6F00EF; // Primary Color
--disclosure-color-active: #a9a9a9; // Active State
--disclosure-color-default: #d3d3d3; // Default States
--disclosure-color-interactive: #666; // Interactive State
--disclosure-color-selected: var(--disclosure-base-color); // Selected States
}
// Disclosure Button
.disclosure--btn {
background-color: var(--disclosure-color-default) ;
border: 0;
color: inherit;
cursor: pointer;
display: grid;
font-size: inherit;
grid-auto-flow: column;
line-height: normal;
padding: 1em;
position: relative;
text-align: start;
width: 100%;
// Accessibility: Focus and hover states must meet a 3:1 color ratio between background color and foreground text.
// The project designer should be providing this state. Also, never remove focus outlines! Either redesign them or
// design an alternative focus state. Learn: https://webaim.org/articles/contrast/
&:focus-visible, &:hover {
background-color: var(--disclosure-color-active);
}
&:focus-visible {
outline-offset: -5px;
}
&[aria-expanded="true"] {
background-color: var(--disclosure-color-selected);
color: #fff;
// Disclosure Arrow: State
.disclosure--arrow {
border-block-end-color: #fff;
border-inline-start-color: #fff;
transform: rotate(135deg);
translate: 0 calc(8rem/16);
}
}
}
// Disclosure Heading
.disclosure--heading {
all: unset;
display: contents;
}
// Disclosure Arrow
.disclosure--arrow {
block-size: var(--disclosure-arrow-size);
border-width: var(--disclosure-arrow-border);
border-block-color: transparent var(--disclosure-color-selected);
border-block-start-width: 0;
border-inline-color: var(--disclosure-color-selected) transparent;
border-inline-end-width: 0;
border-style: solid;
content: "";
direction: ltr;
display: block;
inline-size: var(--disclosure-arrow-size);
justify-self: end;
transform: rotate(-45deg);
}
// Disclosure Content
.disclosure--content {
background-color: var(--disclosure-color-default);
display: none;
overflow: hidden;
padding: 1em;
&[data-animation] {
@media (prefers-reduced-motion: no-preference) {
transition: display 0s, max-height 3s allow-discrete;
}
}
}
// Persistent State
.disclosure--btn, .disclosure--heading {
&[data-persistent] {
@media(min-width: $disclosure-breakpoint) {
display: none;
+ .disclosure--content {
display: block;
}
}
}
}
// Viewport Context
.disclosure--btn, .disclosure--heading {
&[data-context], &[data-disclosure-viewport] {
@media(min-width: $disclosure-breakpoint) {
padding: 0;
pointer-events: none;
visibility: hidden;
.disclosure--btn {
padding: inherit;
pointer-events: inherit;
visibility: inherit;
}
span:not([aria-hidden]) {
color: var(--disclosure-base-color);
font-weight: 700;
visibility: visible;
}
// If icon present
span[aria-hidden] {
display: none;
}
+ .disclosure--content {
background-color: transparent;
display: block;
padding: 0;
}
}
}
}
// Disclosure Event
.disclosure--btn[aria-expanded="true"] + .disclosure--content, .disclosure--heading:has(.disclosure--btn[aria-expanded="true"]) + .disclosure--content {
display: block;
&[data-animation] {
max-height: 5000px;
@starting-style {
max-height: 0;
}
}
}/*!
Radancy Component Library: Disclosure
Contributor(s):
Michael "Spell" Spellacy
*/
(() => {
"use strict";
// Display which Disclosure is in use via console:
console.log("%cDisclosure%cv2.4.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;");
// Commonly used Classes, Data Attributes, States, Strings, etc.
const disclosureButtonClass = ".disclosure--btn";
const disclosureButtons = document.querySelectorAll(disclosureButtonClass);
const disclosureArrowClassName = "disclosure--arrow";
const disclosureHeadingClass = ".disclosure--heading";
const disclosureDataDefaultOpen = "data-open";
const disclosureDataEnableAnchor = "data-enable-anchor";
const disclosureDataRemoveArrow = "data-remove-arrow";
// Add Listener and other needed attributes to disclosure button
disclosureButtons.forEach((button, index) => {
const count = index + 1;
button.setAttribute("aria-expanded", "false");
let thisButtonID, thisContentID;
if (button.hasAttribute("id")) {
// Check for custom ID on button.
thisButtonID = button.getAttribute("id");
thisContentID = `${thisButtonID}-content`;
} else {
// Else, add dynamic ID.
thisButtonID = `disclosure-btn-${count}`;
thisContentID = `disclosure-content-${count}`;
}
// Set ID and aria-controls on button.
button.setAttribute("id", thisButtonID);
button.setAttribute("aria-controls", thisContentID);
if (button.closest(disclosureHeadingClass)) {
// If button contains heading...
button.closest(disclosureHeadingClass).nextElementSibling.setAttribute("id", thisContentID);
} else {
button.nextElementSibling.setAttribute("id", thisContentID);
}
// If custom arrow not needed.
if (!button.hasAttribute(disclosureDataRemoveArrow)) {
const toggleState = document.createElement("span");
toggleState.setAttribute("aria-hidden", "true");
toggleState.classList.add(disclosureArrowClassName);
button.append(toggleState);
}
button.addEventListener("click", () => {
const isExpanded = button.getAttribute("aria-expanded") === "true";
button.setAttribute("aria-expanded", isExpanded ? "false" : "true");
if (button.hasAttribute(disclosureDataEnableAnchor)) {
history.pushState(null, null, `#${button.id}`);
}
});
// Open desired disclosure.
if (button.hasAttribute(disclosureDataDefaultOpen)) {
button.setAttribute("aria-expanded", "true");
}
});
// Open selected disclosure via URL
const url = document.location.href;
const hash = url.split("#");
const disclosureID = document.getElementById(hash[1]);
if(disclosureID) {
const disclosureTarget = document.querySelector(disclosureButtonClass + "#" + disclosureID.id);
if (disclosureTarget) {
disclosureTarget.setAttribute("aria-expanded", "true");
disclosureTarget.focus();
}
}
})();Purple ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem 42 rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.
Reminder: A disclosure is intended for (mostly) single-purpose use. If you need to group multiple disclosures, such as in a FAQ or similar layout, please use the Accordion component.
<h3 class="disclosure--heading"><button class="disclosure--btn">What is the answer to life, the universe, and everything?</button></h3>
<div class="disclosure--content">
<p>Purple ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem <strong>42</strong> rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.</p>
</div>/*!
Radancy Component Library: Disclosure
Contributor(s):
Michael "Spell" Spellacy
Dependencies: Sass
*/
// Sass Variables
$disclosure-breakpoint: 60em;
:root {
--disclosure-arrow-size: 0.8em; // Toggle Arrow Size
--disclosure-arrow-border: calc(2rem / 16); // Toggle Arrow Border
--disclosure-base-color: #6F00EF; // Primary Color
--disclosure-color-active: #a9a9a9; // Active State
--disclosure-color-default: #d3d3d3; // Default States
--disclosure-color-interactive: #666; // Interactive State
--disclosure-color-selected: var(--disclosure-base-color); // Selected States
}
// Disclosure Button
.disclosure--btn {
background-color: var(--disclosure-color-default) ;
border: 0;
color: inherit;
cursor: pointer;
display: grid;
font-size: inherit;
grid-auto-flow: column;
line-height: normal;
padding: 1em;
position: relative;
text-align: start;
width: 100%;
// Accessibility: Focus and hover states must meet a 3:1 color ratio between background color and foreground text.
// The project designer should be providing this state. Also, never remove focus outlines! Either redesign them or
// design an alternative focus state. Learn: https://webaim.org/articles/contrast/
&:focus-visible, &:hover {
background-color: var(--disclosure-color-active);
}
&:focus-visible {
outline-offset: -5px;
}
&[aria-expanded="true"] {
background-color: var(--disclosure-color-selected);
color: #fff;
// Disclosure Arrow: State
.disclosure--arrow {
border-block-end-color: #fff;
border-inline-start-color: #fff;
transform: rotate(135deg);
translate: 0 calc(8rem/16);
}
}
}
// Disclosure Heading
.disclosure--heading {
all: unset;
display: contents;
}
// Disclosure Arrow
.disclosure--arrow {
block-size: var(--disclosure-arrow-size);
border-width: var(--disclosure-arrow-border);
border-block-color: transparent var(--disclosure-color-selected);
border-block-start-width: 0;
border-inline-color: var(--disclosure-color-selected) transparent;
border-inline-end-width: 0;
border-style: solid;
content: "";
direction: ltr;
display: block;
inline-size: var(--disclosure-arrow-size);
justify-self: end;
transform: rotate(-45deg);
}
// Disclosure Content
.disclosure--content {
background-color: var(--disclosure-color-default);
display: none;
overflow: hidden;
padding: 1em;
&[data-animation] {
@media (prefers-reduced-motion: no-preference) {
transition: display 0s, max-height 3s allow-discrete;
}
}
}
// Persistent State
.disclosure--btn, .disclosure--heading {
&[data-persistent] {
@media(min-width: $disclosure-breakpoint) {
display: none;
+ .disclosure--content {
display: block;
}
}
}
}
// Viewport Context
.disclosure--btn, .disclosure--heading {
&[data-context], &[data-disclosure-viewport] {
@media(min-width: $disclosure-breakpoint) {
padding: 0;
pointer-events: none;
visibility: hidden;
.disclosure--btn {
padding: inherit;
pointer-events: inherit;
visibility: inherit;
}
span:not([aria-hidden]) {
color: var(--disclosure-base-color);
font-weight: 700;
visibility: visible;
}
// If icon present
span[aria-hidden] {
display: none;
}
+ .disclosure--content {
background-color: transparent;
display: block;
padding: 0;
}
}
}
}
// Disclosure Event
.disclosure--btn[aria-expanded="true"] + .disclosure--content, .disclosure--heading:has(.disclosure--btn[aria-expanded="true"]) + .disclosure--content {
display: block;
&[data-animation] {
max-height: 5000px;
@starting-style {
max-height: 0;
}
}
}/*!
Radancy Component Library: Disclosure
Contributor(s):
Michael "Spell" Spellacy
*/
(() => {
"use strict";
// Display which Disclosure is in use via console:
console.log("%cDisclosure%cv2.4.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;");
// Commonly used Classes, Data Attributes, States, Strings, etc.
const disclosureButtonClass = ".disclosure--btn";
const disclosureButtons = document.querySelectorAll(disclosureButtonClass);
const disclosureArrowClassName = "disclosure--arrow";
const disclosureHeadingClass = ".disclosure--heading";
const disclosureDataDefaultOpen = "data-open";
const disclosureDataEnableAnchor = "data-enable-anchor";
const disclosureDataRemoveArrow = "data-remove-arrow";
// Add Listener and other needed attributes to disclosure button
disclosureButtons.forEach((button, index) => {
const count = index + 1;
button.setAttribute("aria-expanded", "false");
let thisButtonID, thisContentID;
if (button.hasAttribute("id")) {
// Check for custom ID on button.
thisButtonID = button.getAttribute("id");
thisContentID = `${thisButtonID}-content`;
} else {
// Else, add dynamic ID.
thisButtonID = `disclosure-btn-${count}`;
thisContentID = `disclosure-content-${count}`;
}
// Set ID and aria-controls on button.
button.setAttribute("id", thisButtonID);
button.setAttribute("aria-controls", thisContentID);
if (button.closest(disclosureHeadingClass)) {
// If button contains heading...
button.closest(disclosureHeadingClass).nextElementSibling.setAttribute("id", thisContentID);
} else {
button.nextElementSibling.setAttribute("id", thisContentID);
}
// If custom arrow not needed.
if (!button.hasAttribute(disclosureDataRemoveArrow)) {
const toggleState = document.createElement("span");
toggleState.setAttribute("aria-hidden", "true");
toggleState.classList.add(disclosureArrowClassName);
button.append(toggleState);
}
button.addEventListener("click", () => {
const isExpanded = button.getAttribute("aria-expanded") === "true";
button.setAttribute("aria-expanded", isExpanded ? "false" : "true");
if (button.hasAttribute(disclosureDataEnableAnchor)) {
history.pushState(null, null, `#${button.id}`);
}
});
// Open desired disclosure.
if (button.hasAttribute(disclosureDataDefaultOpen)) {
button.setAttribute("aria-expanded", "true");
}
});
// Open selected disclosure via URL
const url = document.location.href;
const hash = url.split("#");
const disclosureID = document.getElementById(hash[1]);
if(disclosureID) {
const disclosureTarget = document.querySelector(disclosureButtonClass + "#" + disclosureID.id);
if (disclosureTarget) {
disclosureTarget.setAttribute("aria-expanded", "true");
disclosureTarget.focus();
}
}
})();Purple ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem 42 rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.
Note: Reduce your screen size to reveal the disclosure button. In some cases, we may only require a discosure to be present on mobile, but not on desktop.
Reminder: A disclosure is intended for (mostly) single-purpose use. If you need to group multiple disclosures, such as in a FAQ or similar layout, please use the Accordion component.
Warning: This approach should be used sparingly. Try to avoid removing interactive components based on screen size, as it can disrupt usability. If a user zooms in and focuses on a button, they will lose focus when zooming out because the button or button visibility is removed, which can be disorienting.
<button class="disclosure--btn" data-persistent>Open Me</button>
<div class="disclosure--content">
<p>Purple ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem <strong>42</strong> rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.</p>
</div>/*!
Radancy Component Library: Disclosure
Contributor(s):
Michael "Spell" Spellacy
Dependencies: Sass
*/
// Sass Variables
$disclosure-breakpoint: 60em;
:root {
--disclosure-arrow-size: 0.8em; // Toggle Arrow Size
--disclosure-arrow-border: calc(2rem / 16); // Toggle Arrow Border
--disclosure-base-color: #6F00EF; // Primary Color
--disclosure-color-active: #a9a9a9; // Active State
--disclosure-color-default: #d3d3d3; // Default States
--disclosure-color-interactive: #666; // Interactive State
--disclosure-color-selected: var(--disclosure-base-color); // Selected States
}
// Disclosure Button
.disclosure--btn {
background-color: var(--disclosure-color-default) ;
border: 0;
color: inherit;
cursor: pointer;
display: grid;
font-size: inherit;
grid-auto-flow: column;
line-height: normal;
padding: 1em;
position: relative;
text-align: start;
width: 100%;
// Accessibility: Focus and hover states must meet a 3:1 color ratio between background color and foreground text.
// The project designer should be providing this state. Also, never remove focus outlines! Either redesign them or
// design an alternative focus state. Learn: https://webaim.org/articles/contrast/
&:focus-visible, &:hover {
background-color: var(--disclosure-color-active);
}
&:focus-visible {
outline-offset: -5px;
}
&[aria-expanded="true"] {
background-color: var(--disclosure-color-selected);
color: #fff;
// Disclosure Arrow: State
.disclosure--arrow {
border-block-end-color: #fff;
border-inline-start-color: #fff;
transform: rotate(135deg);
translate: 0 calc(8rem/16);
}
}
}
// Disclosure Heading
.disclosure--heading {
all: unset;
display: contents;
}
// Disclosure Arrow
.disclosure--arrow {
block-size: var(--disclosure-arrow-size);
border-width: var(--disclosure-arrow-border);
border-block-color: transparent var(--disclosure-color-selected);
border-block-start-width: 0;
border-inline-color: var(--disclosure-color-selected) transparent;
border-inline-end-width: 0;
border-style: solid;
content: "";
direction: ltr;
display: block;
inline-size: var(--disclosure-arrow-size);
justify-self: end;
transform: rotate(-45deg);
}
// Disclosure Content
.disclosure--content {
background-color: var(--disclosure-color-default);
display: none;
overflow: hidden;
padding: 1em;
&[data-animation] {
@media (prefers-reduced-motion: no-preference) {
transition: display 0s, max-height 3s allow-discrete;
}
}
}
// Persistent State
.disclosure--btn, .disclosure--heading {
&[data-persistent] {
@media(min-width: $disclosure-breakpoint) {
display: none;
+ .disclosure--content {
display: block;
}
}
}
}
// Viewport Context
.disclosure--btn, .disclosure--heading {
&[data-context], &[data-disclosure-viewport] {
@media(min-width: $disclosure-breakpoint) {
padding: 0;
pointer-events: none;
visibility: hidden;
.disclosure--btn {
padding: inherit;
pointer-events: inherit;
visibility: inherit;
}
span:not([aria-hidden]) {
color: var(--disclosure-base-color);
font-weight: 700;
visibility: visible;
}
// If icon present
span[aria-hidden] {
display: none;
}
+ .disclosure--content {
background-color: transparent;
display: block;
padding: 0;
}
}
}
}
// Disclosure Event
.disclosure--btn[aria-expanded="true"] + .disclosure--content, .disclosure--heading:has(.disclosure--btn[aria-expanded="true"]) + .disclosure--content {
display: block;
&[data-animation] {
max-height: 5000px;
@starting-style {
max-height: 0;
}
}
}/*!
Radancy Component Library: Disclosure
Contributor(s):
Michael "Spell" Spellacy
*/
(() => {
"use strict";
// Display which Disclosure is in use via console:
console.log("%cDisclosure%cv2.4.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;");
// Commonly used Classes, Data Attributes, States, Strings, etc.
const disclosureButtonClass = ".disclosure--btn";
const disclosureButtons = document.querySelectorAll(disclosureButtonClass);
const disclosureArrowClassName = "disclosure--arrow";
const disclosureHeadingClass = ".disclosure--heading";
const disclosureDataDefaultOpen = "data-open";
const disclosureDataEnableAnchor = "data-enable-anchor";
const disclosureDataRemoveArrow = "data-remove-arrow";
// Add Listener and other needed attributes to disclosure button
disclosureButtons.forEach((button, index) => {
const count = index + 1;
button.setAttribute("aria-expanded", "false");
let thisButtonID, thisContentID;
if (button.hasAttribute("id")) {
// Check for custom ID on button.
thisButtonID = button.getAttribute("id");
thisContentID = `${thisButtonID}-content`;
} else {
// Else, add dynamic ID.
thisButtonID = `disclosure-btn-${count}`;
thisContentID = `disclosure-content-${count}`;
}
// Set ID and aria-controls on button.
button.setAttribute("id", thisButtonID);
button.setAttribute("aria-controls", thisContentID);
if (button.closest(disclosureHeadingClass)) {
// If button contains heading...
button.closest(disclosureHeadingClass).nextElementSibling.setAttribute("id", thisContentID);
} else {
button.nextElementSibling.setAttribute("id", thisContentID);
}
// If custom arrow not needed.
if (!button.hasAttribute(disclosureDataRemoveArrow)) {
const toggleState = document.createElement("span");
toggleState.setAttribute("aria-hidden", "true");
toggleState.classList.add(disclosureArrowClassName);
button.append(toggleState);
}
button.addEventListener("click", () => {
const isExpanded = button.getAttribute("aria-expanded") === "true";
button.setAttribute("aria-expanded", isExpanded ? "false" : "true");
if (button.hasAttribute(disclosureDataEnableAnchor)) {
history.pushState(null, null, `#${button.id}`);
}
});
// Open desired disclosure.
if (button.hasAttribute(disclosureDataDefaultOpen)) {
button.setAttribute("aria-expanded", "true");
}
});
// Open selected disclosure via URL
const url = document.location.href;
const hash = url.split("#");
const disclosureID = document.getElementById(hash[1]);
if(disclosureID) {
const disclosureTarget = document.querySelector(disclosureButtonClass + "#" + disclosureID.id);
if (disclosureTarget) {
disclosureTarget.setAttribute("aria-expanded", "true");
disclosureTarget.focus();
}
}
})();Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.
Note: In some scenarios, we may only want the disclosure to be present on smaller viewports. In such cases, it is crucial to ensure that accessibility on larger screens is not compromised by leaving buttons accessible to assistive technologies. To see this solution in action, try pressing or tabbing to the headings in larger viewport sizes. As you'll notice, the headings are not interactive and all content that would normally be collapsed is revealed, which is exactly what we want. However, when you change the viewport to a smaller size, the component then becomes a traditional accordion. This kind of behavior can often be found in the footer of applications or website, where space is more limited on smaller screens.
Reminder: A disclosure is intended for (mostly) single-purpose use. If you need to group multiple disclosures, such as in a FAQ or similar layout, please use the Accordion component.
Warning: This approach should be used sparingly. Try to avoid removing interactive components based on screen size, as it can disrupt usability. If a user zooms in and focuses on a button, they will lose focus when zooming out because the button or button visibility is removed, which can be disorienting.
<h3 class="disclosure--heading" data-context><button class="disclosure--btn"><span>Learn More</span></button></span></h3>
<div class="disclosure--content">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam congue, urna eu efficitur accumsan, massa sem rhoncus elit, eu mattis erat metus gravida dolor. Maecenas imperdiet sodales dolor, sit amet malesuada lorem tincidunt in. Nunc a risus augue. Sed pellentesque pharetra iaculis. Donec gravida risus ut placerat venenatis. Integer sed erat eget risus rutrum condimentum. Curabitur tincidunt nisl ornare, viverra est eget, condimentum lectus. Integer pretium justo ac odio vestibulum ornare. Nullam mi risus, faucibus lacinia justo et, auctor vehicula lectus.</p>
</div>/*!
Radancy Component Library: Disclosure
Contributor(s):
Michael "Spell" Spellacy
Dependencies: Sass
*/
// Sass Variables
$disclosure-breakpoint: 60em;
:root {
--disclosure-arrow-size: 0.8em; // Toggle Arrow Size
--disclosure-arrow-border: calc(2rem / 16); // Toggle Arrow Border
--disclosure-base-color: #6F00EF; // Primary Color
--disclosure-color-active: #a9a9a9; // Active State
--disclosure-color-default: #d3d3d3; // Default States
--disclosure-color-interactive: #666; // Interactive State
--disclosure-color-selected: var(--disclosure-base-color); // Selected States
}
// Disclosure Button
.disclosure--btn {
background-color: var(--disclosure-color-default) ;
border: 0;
color: inherit;
cursor: pointer;
display: grid;
font-size: inherit;
grid-auto-flow: column;
line-height: normal;
padding: 1em;
position: relative;
text-align: start;
width: 100%;
// Accessibility: Focus and hover states must meet a 3:1 color ratio between background color and foreground text.
// The project designer should be providing this state. Also, never remove focus outlines! Either redesign them or
// design an alternative focus state. Learn: https://webaim.org/articles/contrast/
&:focus-visible, &:hover {
background-color: var(--disclosure-color-active);
}
&:focus-visible {
outline-offset: -5px;
}
&[aria-expanded="true"] {
background-color: var(--disclosure-color-selected);
color: #fff;
// Disclosure Arrow: State
.disclosure--arrow {
border-block-end-color: #fff;
border-inline-start-color: #fff;
transform: rotate(135deg);
translate: 0 calc(8rem/16);
}
}
}
// Disclosure Heading
.disclosure--heading {
all: unset;
display: contents;
}
// Disclosure Arrow
.disclosure--arrow {
block-size: var(--disclosure-arrow-size);
border-width: var(--disclosure-arrow-border);
border-block-color: transparent var(--disclosure-color-selected);
border-block-start-width: 0;
border-inline-color: var(--disclosure-color-selected) transparent;
border-inline-end-width: 0;
border-style: solid;
content: "";
direction: ltr;
display: block;
inline-size: var(--disclosure-arrow-size);
justify-self: end;
transform: rotate(-45deg);
}
// Disclosure Content
.disclosure--content {
background-color: var(--disclosure-color-default);
display: none;
overflow: hidden;
padding: 1em;
&[data-animation] {
@media (prefers-reduced-motion: no-preference) {
transition: display 0s, max-height 3s allow-discrete;
}
}
}
// Persistent State
.disclosure--btn, .disclosure--heading {
&[data-persistent] {
@media(min-width: $disclosure-breakpoint) {
display: none;
+ .disclosure--content {
display: block;
}
}
}
}
// Viewport Context
.disclosure--btn, .disclosure--heading {
&[data-context], &[data-disclosure-viewport] {
@media(min-width: $disclosure-breakpoint) {
padding: 0;
pointer-events: none;
visibility: hidden;
.disclosure--btn {
padding: inherit;
pointer-events: inherit;
visibility: inherit;
}
span:not([aria-hidden]) {
color: var(--disclosure-base-color);
font-weight: 700;
visibility: visible;
}
// If icon present
span[aria-hidden] {
display: none;
}
+ .disclosure--content {
background-color: transparent;
display: block;
padding: 0;
}
}
}
}
// Disclosure Event
.disclosure--btn[aria-expanded="true"] + .disclosure--content, .disclosure--heading:has(.disclosure--btn[aria-expanded="true"]) + .disclosure--content {
display: block;
&[data-animation] {
max-height: 5000px;
@starting-style {
max-height: 0;
}
}
}/*!
Radancy Component Library: Disclosure
Contributor(s):
Michael "Spell" Spellacy
*/
(() => {
"use strict";
// Display which Disclosure is in use via console:
console.log("%cDisclosure%cv2.4.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;");
// Commonly used Classes, Data Attributes, States, Strings, etc.
const disclosureButtonClass = ".disclosure--btn";
const disclosureButtons = document.querySelectorAll(disclosureButtonClass);
const disclosureArrowClassName = "disclosure--arrow";
const disclosureHeadingClass = ".disclosure--heading";
const disclosureDataDefaultOpen = "data-open";
const disclosureDataEnableAnchor = "data-enable-anchor";
const disclosureDataRemoveArrow = "data-remove-arrow";
// Add Listener and other needed attributes to disclosure button
disclosureButtons.forEach((button, index) => {
const count = index + 1;
button.setAttribute("aria-expanded", "false");
let thisButtonID, thisContentID;
if (button.hasAttribute("id")) {
// Check for custom ID on button.
thisButtonID = button.getAttribute("id");
thisContentID = `${thisButtonID}-content`;
} else {
// Else, add dynamic ID.
thisButtonID = `disclosure-btn-${count}`;
thisContentID = `disclosure-content-${count}`;
}
// Set ID and aria-controls on button.
button.setAttribute("id", thisButtonID);
button.setAttribute("aria-controls", thisContentID);
if (button.closest(disclosureHeadingClass)) {
// If button contains heading...
button.closest(disclosureHeadingClass).nextElementSibling.setAttribute("id", thisContentID);
} else {
button.nextElementSibling.setAttribute("id", thisContentID);
}
// If custom arrow not needed.
if (!button.hasAttribute(disclosureDataRemoveArrow)) {
const toggleState = document.createElement("span");
toggleState.setAttribute("aria-hidden", "true");
toggleState.classList.add(disclosureArrowClassName);
button.append(toggleState);
}
button.addEventListener("click", () => {
const isExpanded = button.getAttribute("aria-expanded") === "true";
button.setAttribute("aria-expanded", isExpanded ? "false" : "true");
if (button.hasAttribute(disclosureDataEnableAnchor)) {
history.pushState(null, null, `#${button.id}`);
}
});
// Open desired disclosure.
if (button.hasAttribute(disclosureDataDefaultOpen)) {
button.setAttribute("aria-expanded", "true");
}
});
// Open selected disclosure via URL
const url = document.location.href;
const hash = url.split("#");
const disclosureID = document.getElementById(hash[1]);
if(disclosureID) {
const disclosureTarget = document.querySelector(disclosureButtonClass + "#" + disclosureID.id);
if (disclosureTarget) {
disclosureTarget.setAttribute("aria-expanded", "true");
disclosureTarget.focus();
}
}
})();Properties Anchor (Properties)
Use the following properties to configure this component.
| Attribute | Applies To | Note | Description |
|---|---|---|---|
data-animation |
.disclosure--content |
Boolean, Optional | Used to enable content to be animated when opened. Please note that the default animation leverages @starting-style at-rule. |
data-context |
.disclosure--btn, .disclosure--heading |
Boolean, Optional | Used to allow the disclosure to become non-interactive on larger viewport sizes, while maintaining interactivity on mobile. The older attribute, data-disclosure-viewport has been depracted and should no longer be used. |
data-enable-anchor |
.disclosure--btn |
Boolean, Optional | Used to enable the anchor that appears in the address bar when a disclosure is pressed. Including an anchor can be useful for tracking and sharing specific content. |
data-open |
.disclosure--btn |
Boolean, Optional | Specifies that content should be open on page load. If not specified, no content will be opened. |
data-persistent |
.disclosure--btn, .disclosure--heading |
Boolean, Optional | Specifies that the content should remain persistent and always open in larger viewports. Attribute must be included on both the button and content. Must not be used with .disclosure--heading. |
data-remove-arrow |
.disclosure--btn |
Boolean, Optional | By default, all buttons include a span element for icons. If this is not desirable, you can remove it by adding this attribute and using your own inline or CSS icon. For custom inline icons, ensure they are hidden from assistive technologies by using aria-hidden="true". |
| Class | Applies To | Note | Description |
|---|---|---|---|
.disclosure--btn |
button |
Mandatory | Required on your disclosure button. |
.disclosure--content |
div, section |
Mandatory | Required on your disclosure content. |
.disclosure--heading |
h1, h2, h3, h4, h5, h6 |
Optional | Include this class on any heading you might have that wraps your button. A heading should always wrap a button and not the other way around. |
Release Notes Anchor (Release Notes)
Keep up to date on major changes to this component.
- Bug
- January 31, 2025: Fixed issue with script breaking when URL contains a page fragment that is not used by the disclosure. Addressed some redundancy as well. Thanks, James!
- Feature
- January 29, 2025: Added
data-persistent, a new attribute for.disclosure--btn, allowing triggers to be hidden on desktop but visible on mobile. - Behavior
- January 29, 2025: Reinstated the viewport-friendly method, allowing triggers to be non-interactive on larger viewports. The attribute is now called
data-contextand should be used going forward.data-disclosure-viewportis deprecated and will be removed in a future release. - Note
- April 24, 2025: Upgraded component to ES6. Thanks, Donte!
Report Issues
Find a bug? Want a new feature? Report it on JIRA. You're so awesome!