<div class="js-o-accordion o-accordion">
    <h3 class="js-accordion__header" data-accordion-opened="true">

        Quisque non molestie arcu
    </h3>
    <div class="js-accordion__panel">
        <div class="o-accordion__panel__content">
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ut elit lacinia, feugiat felis sit amet, congue ante. Morbi vel egestas mi. Nulla urna sapien, gravida et nisl ac, maximus euismod ipsum. Vivamus condimentum, massa non convallis hendrerit, orci mi porttitor nisi, at commodo purus magna non nisi. Duis feugiat lectus in sapien mollis, ac volutpat leo elementum. Nullam euismod massa a nulla placerat sagittis. Integer id purus a dolor fermentum mollis vel feugiat dui. Nullam neque diam, mattis nec cursus at, facilisis nec diam.</p>
            <p>Proin faucibus pretium orci, eu tristique augue condimentum at. Suspendisse potenti. Donec ut luctus eros. Nam justo nunc, facilisis lobortis hendrerit sodales, fermentum at purus. Proin eget elementum nulla, nec tincidunt lacus. Mauris massa eros, interdum eget nunc id, molestie semper libero. Vivamus tortor ex, viverra ut varius vel, finibus hendrerit nunc. Morbi pulvinar arcu erat, consectetu mollis leo vulputate eu.</p>
        </div>
    </div>
    <h3 class="js-accordion__header">

        Nullam neque diam, mattis nec cursus at
    </h3>
    <div class="js-accordion__panel">
        <div class="o-accordion__panel__content">
            <ul>
                <li>Quisque non molestie arcu</li>
                <li>Nullam vehicula eros nec lorem congue mattis</li>
                <li>Pellentesque rutrum lacinia diam in finibus</li>
                <li>Mauris at risus pulvinar, scelerisque sapien</li>
            </ul>
        </div>
    </div>
    <h3 class="js-accordion__header">

        Suspendisse potenti
    </h3>
    <div class="js-accordion__panel">
        <div class="o-accordion__panel__content">
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ut elit lacinia, feugiat felis sit amet, congue ante. Morbi vel egestas mi. Nulla urna sapien, gravida et nisl ac, maximus euismod ipsum. Vivamus condimentum, massa non convallis hendrerit, orci mi porttitor nisi, at commodo purus magna non nisi. Duis feugiat lectus in sapien mollis, ac volutpat leo elementum. Nullam euismod massa a nulla placerat sagittis. Integer id purus a dolor fermentum mollis vel feugiat dui. Nullam neque diam, mattis nec cursus at, facilisis nec diam.</p>
            <p>Proin faucibus pretium orci, eu tristique augue condimentum at. Suspendisse potenti. Donec ut luctus eros. Nam justo nunc, facilisis lobortis hendrerit sodales, fermentum at purus. Proin eget elementum nulla, nec tincidunt lacus. Mauris massa eros, interdum eget nunc id, molestie semper libero. Vivamus tortor ex, viverra ut varius vel, finibus hendrerit nunc. Morbi pulvinar arcu erat, consectetu mollis leo vulputate eu.</p>
        </div>
    </div>
    <h3 class="js-accordion__header">

        Mauris at risus pulvinar, scelerisque sapien
    </h3>
    <div class="js-accordion__panel">
        <div class="o-accordion__panel__content">
            <ul>
                <li>Quisque non molestie arcu</li>
                <li>Nullam vehicula eros nec lorem congue mattis</li>
                <li>Pellentesque rutrum lacinia diam in finibus</li>
                <li>Mauris at risus pulvinar, scelerisque sapien</li>
            </ul>
        </div>
    </div>
    <h3 class="js-accordion__header">

        Proin faucibus pretium orci
    </h3>
    <div class="js-accordion__panel">
        <div class="o-accordion__panel__content">
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ut elit lacinia, feugiat felis sit amet, congue ante. Morbi vel egestas mi. Nulla urna sapien, gravida et nisl ac, maximus euismod ipsum. Vivamus condimentum, massa non convallis hendrerit, orci mi porttitor nisi, at commodo purus magna non nisi. Duis feugiat lectus in sapien mollis, ac volutpat leo elementum. Nullam euismod massa a nulla placerat sagittis. Integer id purus a dolor fermentum mollis vel feugiat dui. Nullam neque diam, mattis nec cursus at, facilisis nec diam.</p>
            <p>Proin faucibus pretium orci, eu tristique augue condimentum at. Suspendisse potenti. Donec ut luctus eros. Nam justo nunc, facilisis lobortis hendrerit sodales, fermentum at purus. Proin eget elementum nulla, nec tincidunt lacus. Mauris massa eros, interdum eget nunc id, molestie semper libero. Vivamus tortor ex, viverra ut varius vel, finibus hendrerit nunc. Morbi pulvinar arcu erat, consectetu mollis leo vulputate eu.</p>
        </div>
    </div>
    <h3 class="js-accordion__header">

        Proin faucibus pretium orci
    </h3>
    <div class="js-accordion__panel">
        <div class="o-accordion__panel__content">
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ut elit lacinia, feugiat felis sit amet, congue ante. Morbi vel egestas mi. Nulla urna sapien, gravida et nisl ac, maximus euismod ipsum. Vivamus condimentum, massa non convallis hendrerit, orci mi porttitor nisi, at commodo purus magna non nisi. Duis feugiat lectus in sapien mollis, ac volutpat leo elementum. Nullam euismod massa a nulla placerat sagittis. Integer id purus a dolor fermentum mollis vel feugiat dui. Nullam neque diam, mattis nec cursus at, facilisis nec diam.</p>
            <p>Proin faucibus pretium orci, eu tristique augue condimentum at. Suspendisse potenti. Donec ut luctus eros. Nam justo nunc, facilisis lobortis hendrerit sodales, fermentum at purus. Proin eget elementum nulla, nec tincidunt lacus. Mauris massa eros, interdum eget nunc id, molestie semper libero. Vivamus tortor ex, viverra ut varius vel, finibus hendrerit nunc. Morbi pulvinar arcu erat, consectetu mollis leo vulputate eu.</p>
        </div>
    </div>
</div>
<div style="padding: 20px">
    <button type="button" class="a-button" id="addAccordion"><span class="a-button__text">Lägg till</span></button>
</div>
<script>
    document.getElementById('addAccordion').addEventListener('click', function() {
        const html = `
			<h3 class="js-accordion__header">
				Quisque non molestie arcu
			</h3>
			<div class="js-accordion__panel">
				<div class="o-accordion__panel__content">
					<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ut elit lacinia, feugiat felis sit amet, congue ante. Morbi vel egestas mi. Nulla urna sapien, gravida et nisl ac, maximus euismod ipsum. Vivamus condimentum, massa non convallis hendrerit, orci mi porttitor nisi, at commodo purus magna non nisi. Duis feugiat lectus in sapien mollis, ac volutpat leo elementum. Nullam euismod massa a nulla placerat sagittis. Integer id purus a dolor fermentum mollis vel feugiat dui. Nullam neque diam, mattis nec cursus at, facilisis nec diam.</p><p>Proin faucibus pretium orci, eu tristique augue condimentum at. Suspendisse potenti. Donec ut luctus eros. Nam justo nunc, facilisis lobortis hendrerit sodales, fermentum at purus. Proin eget elementum nulla, nec tincidunt lacus. Mauris massa eros, interdum eget nunc id, molestie semper libero. Vivamus tortor ex, viverra ut varius vel, finibus hendrerit nunc. Morbi pulvinar arcu erat, consectetu mollis leo vulputate eu.</p>
				</div>
			</div>
		`;
        const wrapper = document.querySelector('.o-accordion');
        wrapper.insertBefore(document.createRange().createContextualFragment(html), wrapper.firstElementChild);
    });
</script>
<div class="js-o-accordion o-accordion">
	{{#each accordion_item}}
	<h3 class="js-accordion__header{{#if color}} o-accordion__header--background background-{{color}}{{/if}}{{#unless content}} o-accordion__header--no-content{{/unless}}"{{#if is_expanded}} data-accordion-opened="true"{{/if}}>
		{{#if time}}<time class="a-meta o-accordion__header__time">{{time}}</time>{{/if}}
		{{#if heading}}
		{{heading}}
		{{/if}}
	</h3>
	<div class="js-accordion__panel">
		<div class="o-accordion__panel__content">
			{{{content}}}
		</div>
	</div>
	{{/each}}
</div>
{{#unless has_background}}
<div style="padding: 20px">
	<button type="button" class="a-button" id="addAccordion"><span class="a-button__text">Lägg till</span></button>
</div>
<script>
	document.getElementById('addAccordion').addEventListener('click', function () {
		const html = `
			<h3 class="js-accordion__header">
				Quisque non molestie arcu
			</h3>
			<div class="js-accordion__panel">
				<div class="o-accordion__panel__content">
					<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ut elit lacinia, feugiat felis sit amet, congue ante. Morbi vel egestas mi. Nulla urna sapien, gravida et nisl ac, maximus euismod ipsum. Vivamus condimentum, massa non convallis hendrerit, orci mi porttitor nisi, at commodo purus magna non nisi. Duis feugiat lectus in sapien mollis, ac volutpat leo elementum. Nullam euismod massa a nulla placerat sagittis. Integer id purus a dolor fermentum mollis vel feugiat dui. Nullam neque diam, mattis nec cursus at, facilisis nec diam.</p><p>Proin faucibus pretium orci, eu tristique augue condimentum at. Suspendisse potenti. Donec ut luctus eros. Nam justo nunc, facilisis lobortis hendrerit sodales, fermentum at purus. Proin eget elementum nulla, nec tincidunt lacus. Mauris massa eros, interdum eget nunc id, molestie semper libero. Vivamus tortor ex, viverra ut varius vel, finibus hendrerit nunc. Morbi pulvinar arcu erat, consectetu mollis leo vulputate eu.</p>
				</div>
			</div>
		`;

		const wrapper = document.querySelector('.o-accordion');

		wrapper.insertBefore(document.createRange().createContextualFragment(html), wrapper.firstElementChild);
	});
</script>
{{/unless}}
{
  "has_background": false,
  "has_time": false,
  "accordion_item": [
    {
      "heading": "Quisque non molestie arcu",
      "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ut elit lacinia, feugiat felis sit amet, congue ante. Morbi vel egestas mi. Nulla urna sapien, gravida et nisl ac, maximus euismod ipsum. Vivamus condimentum, massa non convallis hendrerit, orci mi porttitor nisi, at commodo purus magna non nisi. Duis feugiat lectus in sapien mollis, ac volutpat leo elementum. Nullam euismod massa a nulla placerat sagittis. Integer id purus a dolor fermentum mollis vel feugiat dui. Nullam neque diam, mattis nec cursus at, facilisis nec diam.</p><p>Proin faucibus pretium orci, eu tristique augue condimentum at. Suspendisse potenti. Donec ut luctus eros. Nam justo nunc, facilisis lobortis hendrerit sodales, fermentum at purus. Proin eget elementum nulla, nec tincidunt lacus. Mauris massa eros, interdum eget nunc id, molestie semper libero. Vivamus tortor ex, viverra ut varius vel, finibus hendrerit nunc. Morbi pulvinar arcu erat, consectetu mollis leo vulputate eu.</p>",
      "color": false,
      "is_expanded": true
    },
    {
      "heading": "Nullam neque diam, mattis nec cursus at",
      "content": "<ul><li>Quisque non molestie arcu</li><li>Nullam vehicula eros nec lorem congue mattis</li><li>Pellentesque rutrum lacinia diam in finibus</li><li>Mauris at risus pulvinar, scelerisque sapien</li></ul>",
      "color": false
    },
    {
      "heading": "Suspendisse potenti",
      "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ut elit lacinia, feugiat felis sit amet, congue ante. Morbi vel egestas mi. Nulla urna sapien, gravida et nisl ac, maximus euismod ipsum. Vivamus condimentum, massa non convallis hendrerit, orci mi porttitor nisi, at commodo purus magna non nisi. Duis feugiat lectus in sapien mollis, ac volutpat leo elementum. Nullam euismod massa a nulla placerat sagittis. Integer id purus a dolor fermentum mollis vel feugiat dui. Nullam neque diam, mattis nec cursus at, facilisis nec diam.</p><p>Proin faucibus pretium orci, eu tristique augue condimentum at. Suspendisse potenti. Donec ut luctus eros. Nam justo nunc, facilisis lobortis hendrerit sodales, fermentum at purus. Proin eget elementum nulla, nec tincidunt lacus. Mauris massa eros, interdum eget nunc id, molestie semper libero. Vivamus tortor ex, viverra ut varius vel, finibus hendrerit nunc. Morbi pulvinar arcu erat, consectetu mollis leo vulputate eu.</p>",
      "color": false
    },
    {
      "heading": "Mauris at risus pulvinar, scelerisque sapien",
      "content": "<ul><li>Quisque non molestie arcu</li><li>Nullam vehicula eros nec lorem congue mattis</li><li>Pellentesque rutrum lacinia diam in finibus</li><li>Mauris at risus pulvinar, scelerisque sapien</li></ul>",
      "color": false
    },
    {
      "heading": "Proin faucibus pretium orci",
      "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ut elit lacinia, feugiat felis sit amet, congue ante. Morbi vel egestas mi. Nulla urna sapien, gravida et nisl ac, maximus euismod ipsum. Vivamus condimentum, massa non convallis hendrerit, orci mi porttitor nisi, at commodo purus magna non nisi. Duis feugiat lectus in sapien mollis, ac volutpat leo elementum. Nullam euismod massa a nulla placerat sagittis. Integer id purus a dolor fermentum mollis vel feugiat dui. Nullam neque diam, mattis nec cursus at, facilisis nec diam.</p><p>Proin faucibus pretium orci, eu tristique augue condimentum at. Suspendisse potenti. Donec ut luctus eros. Nam justo nunc, facilisis lobortis hendrerit sodales, fermentum at purus. Proin eget elementum nulla, nec tincidunt lacus. Mauris massa eros, interdum eget nunc id, molestie semper libero. Vivamus tortor ex, viverra ut varius vel, finibus hendrerit nunc. Morbi pulvinar arcu erat, consectetu mollis leo vulputate eu.</p>",
      "color": false
    },
    {
      "heading": "Proin faucibus pretium orci",
      "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ut elit lacinia, feugiat felis sit amet, congue ante. Morbi vel egestas mi. Nulla urna sapien, gravida et nisl ac, maximus euismod ipsum. Vivamus condimentum, massa non convallis hendrerit, orci mi porttitor nisi, at commodo purus magna non nisi. Duis feugiat lectus in sapien mollis, ac volutpat leo elementum. Nullam euismod massa a nulla placerat sagittis. Integer id purus a dolor fermentum mollis vel feugiat dui. Nullam neque diam, mattis nec cursus at, facilisis nec diam.</p><p>Proin faucibus pretium orci, eu tristique augue condimentum at. Suspendisse potenti. Donec ut luctus eros. Nam justo nunc, facilisis lobortis hendrerit sodales, fermentum at purus. Proin eget elementum nulla, nec tincidunt lacus. Mauris massa eros, interdum eget nunc id, molestie semper libero. Vivamus tortor ex, viverra ut varius vel, finibus hendrerit nunc. Morbi pulvinar arcu erat, consectetu mollis leo vulputate eu.</p>",
      "color": false
    }
  ]
}
  • Content:
    @charset 'UTF-8';
    
    // Extends
    %header {
    	display: flex;
    	position: relative;
    	flex-direction: column;
    	width: 100%;
    	padding: rhythm(2) rhythm(5) rhythm(2) rhythm(2);
    	border: 0;
    	background: transparent;
    	box-shadow: inset 0 -1px 1px rgba($color-cyberspace, 0.2);
    	font-family: $font-family-headings;
    	font-size: rem(17px);
    	text-align: left;
    
    	@include bp-up(md) {
    		font-size: rem(18px);
    	}
    
    	@include bp-up(xl) {
    		font-size: rem(20px);
    	}
    
    	-webkit-appearance: none;
    
    	&::before,
    	&::after {
    		content: '';
    		display: block;
    		position: absolute;
    		top: 50%;
    		right: rem(23px);
    		width: $icon-size-small;
    		height: 3px;
    		transform: translateY(-50%);
    		transform-origin: center center;
    		transition: transform 0.25s ease-out;
    		background-color: var(--cyberspace-color);
    	}
    
    	&::before {
    		transform: rotate(45deg);
    	}
    
    	&::after {
    		right: rem(13px);
    		transform: rotate(-45deg);
    	}
    
    	&[aria-expanded='true'] {
    		box-shadow: none;
    
    		&::after {
    			transform: rotate(-135deg);
    		}
    
    		&::before {
    			transform: rotate(135deg);
    		}
    	}
    
    	@include bp-up(md) {
    		flex-direction: row;
    		align-items: center;
    	}
    }
    
    %panel {
    	padding: 0;
    	transition: visibility 0s ease, max-height 0.25s ease, opacity 0.25s ease;
    	transition-delay: 0s;
    	background-color: var(--snow-color);
    }
    
    %is-visible {
    	visibility: visible;
    	max-height: 10000em; // Rediculous height
    	overflow: visible;
    	transition: visibility 0s ease, max-height 0.25s ease, opacity 0.25s ease;
    	opacity: 1;
    }
    
    %is-hidden {
    	visibility: hidden;
    	max-height: 0;
    	overflow: hidden;
    	transition: visibility 0s ease, max-height 0.25s ease, opacity 0.25s ease;
    	transition-delay: 0.25s, 0s, 0s;
    	opacity: 0;
    }
    
    // Styling before Accordion script kicks in
    .js-accordion {
    	@include e(header) {
    		@extend %header;
    
    		margin-bottom: 0;
    
    		&::before,
    		&::after {
    			display: none;
    		}
    	}
    
    	@include e(panel) {
    		@extend %panel;
    	}
    }
    
    .js {
    	.js-accordion {
    
    		@include e(header) {
    			border-bottom: 1px solid var(--snow-color);
    
    			&[aria-expanded='true'] {
    				border-color: transparent;
    			}
    
    			&::before,
    			&::after {
    				display: block;
    			}
    		}
    	}
    
    	@include organism(accordion) {
    		background-color: lighten($color-ash, 4%);
    
    		@include e(panel) {
    			&[aria-hidden='false'],
    			&:not([aria-hidden='true']) {
    				@extend %is-visible;
    			}
    		}
    
    		@include m(transparent) {
    			background-color: transparent;
    
    			[class*='header'] {
    				box-shadow: none;
    			}
    		}
    	}
    }
    
    .js-o-accordion {
    	> [class*='panel'] {
    		@extend %is-hidden;
    	}
    }
    
    @include organism(accordion) {
    	margin: 0;
    	padding: 0;
    	background-position: top left;
    	list-style: none;
    
    	&::before {
    		@extend %u-visuallyhidden;
    
    		content: $namespace;
    	}
    
    	@include e(row) {
    		pointer-events: none;
    	}
    
    	@include e(header) {
    		@extend %header;
    
    		@include m(inline) {
    			display: inline-flex;
    			width: auto;
    
    			button {
    				padding-right: rhythm(5);
    				padding-left: 0;
    			}
    		}
    
    		@include m(no-border) {
    			button[role='tab'] {
    				border-bottom: 0;
    				box-shadow: none;
    			}
    
    			+ div {
    				border-bottom: 0;
    			}
    		}
    
    		@include m(background) {
    			button {
    				box-shadow: none;
    			}
    		}
    
    		@include m(no-content) {
    			button {
    				cursor: default;
    				pointer-events: none;
    
    				&::before,
    				&::after {
    					display: none !important;
    				}
    			}
    		}
    
    		@include e(time) {
    			margin-top: 0;
    			margin-right: rhythm(2);
    			padding-top: 0;
    			padding-bottom: 0;
    
    			@include bp-up(md) {
    				font-size: 90%;
    			}
    		}
    	}
    
    	@include e(panel) {
    		@extend %panel;
    
    		// Nested to prevent padding when JS is disabled
    		@include e(content) {
    			position: relative;
    			padding: rhythm(3);
    
    			> :last-child {
    				margin-bottom: 0;
    			}
    		}
    
    		@include m(transparent) {
    			background-color: transparent;
    		}
    
    		@include m(ash) {
    			border-radius: 0;
    			background-color: lighten($color-ash, 4%);
    		}
    	}
    
    	@include e(title) {
    		margin-top: 0;
    		margin-bottom: 0;
    		padding-top: 0;
    		padding-bottom: 0;
    
    		&:last-of-type {
    			> button {
    				border-bottom: 0;
    			}
    		}
    	}
    
    	@include e(logo) {
    		margin-bottom: rhythm(2);
    
    		@include bp-up(sm) {
    			margin-right: rhythm(2);
    			margin-bottom: 0;
    		}
    	}
    
    	@include e(list) {
    		display: inline-block;
    		margin-bottom: 0;
    
    		a {
    
    			@extend %word-break;
    
    			color: var(--cyberspace-color);
    			text-decoration: none;
    
    			&:focus,
    			&:hover {
    				text-decoration: underline;
    			}
    		}
    
    		@include e(item) {
    			display: flex;
    			align-items: center;
    			margin-left: 0;
    			pointer-events: initial;
    		}
    
    		@include e(flag) {
    			margin-right: rhythm(1);
    			font-size: rem(32px);
    			line-height: 1;
    		}
    	}
    }
    
    .no-js {
    	@include organism(accordion) {
    		> [class*='panel'] {
    			@extend %is-visible;
    		}
    	}
    }
    
  • URL: /components/raw/accordion/_accordion.scss
  • Filesystem Path: src/organisms/accordion/_accordion.scss
  • Size: 4.7 KB
  • Content:
    import debounce from '../../assets/js/debounce';
    
    require('van11y-accessible-accordion-aria');
    
    const className = 'o-accordion';
    const accordionElement = document.querySelector(`.js-${className}`);
    let oAccordion = null;
    
    function attachAccordion() {
    	if (!oAccordion) {
    		const namespace = getComputedStyle(accordionElement, ':before').content.replace(/["']/g, '');
    
    		oAccordion = window.van11yAccessibleAccordionAria({
    			ACCORDION_PREFIX_IDS: className,
    			ACCORDION_JS: `js-${className}`,
    			ACCORDION_STYLE: `${namespace}${className}`,
    			ACCORDION_TITLE_STYLE: `${namespace}${className}__title`,
    			ACCORDION_HEADER_STYLE: `${namespace}${className}__header`,
    			ACCORDION_PANEL_STYLE: `${namespace}${className}__panel`,
    		});
    	}
    
    	oAccordion.attach();
    }
    
    if (accordionElement) {
    	attachAccordion();
    }
    
    const checkElements = debounce(() => {
    	const accordionElementFresh = document.querySelector(`.js-${className}`);
    
    	if (accordionElementFresh) {
    		attachAccordion();
    	}
    }, 50);
    
    const observeHandler = (mutationsList) => {
    	mutationsList.forEach((mutation) => {
    		if (mutation.type !== 'childList') {
    			return;
    		}
    
    		checkElements();
    	});
    };
    
    const observer = new MutationObserver(observeHandler);
    
    observer.observe(document.body, { childList: true, subtree: true });
    
  • URL: /components/raw/accordion/accordion.js
  • Filesystem Path: src/organisms/accordion/accordion.js
  • Size: 1.3 KB

Accordion (accessible)

This component takes use on the Van11y Accessible Accordion vendor script

More info: https://van11y.net/accessible-accordion/