Tabs

<div data-tab-component>

    <ul class="o-tab-list js-o-tab-list">
        <li class="o-tab-list__item">
            <a class="o-tab-list__link" href="#tab-1" id="tab-namn-1">De här</a>
        </li>
        <li class="o-tab-list__item">
            <a class="o-tab-list__link" href="#tab-2" id="tab-namn-2">Tabbarna</a>
        </li>
        <li class="o-tab-list__item">
            <a class="o-tab-list__link" href="#tab-3" id="tab-namn-3"> Går till elva</a>
        </li>
        <li class="o-tab-list__item">
            <a class="o-tab-list__link" href="#tab-4" id="tab-namn-4"><svg width="20" height="20" viewbox="0 0 32 32">
                    <path d="M31.5 18.2v-4.4h-4.7c-.3-1.4-.8-2.6-1.5-3.7l3.3-3.3-3.1-3.1L22.2 7c-1.2-.8-2.6-1.4-4-1.7V.5h-4.4v4.7c-1.4.2-2.7.8-3.9 1.6L6.7 3.6 3.6 6.7l3.2 3.2c-.8 1.2-1.3 2.5-1.6 3.9H.5v4.4h4.7c.3 1.5.9 2.8 1.7 4l-3.3 3.3 3.1 3.1 3.3-3.3c1.1.7 2.4 1.3 3.7 1.5v4.7h4.4v-4.7c1.4-.3 2.7-.8 3.9-1.6l3.4 3.4 3.1-3.1-3.4-3.4c.8-1.2 1.3-2.5 1.6-3.9h4.8zM16 23.5c-4.1 0-7.5-3.4-7.5-7.5s3.4-7.5 7.5-7.5 7.5 3.4 7.5 7.5-3.4 7.5-7.5 7.5z"></path>
                </svg></a>
        </li>
    </ul>

    <section id="tab-1" class="o-tab-panel">
        <h2>De här</h2>
        <p>Klinisk och min drink. Reserverad potten var nu en kund, men inte bara protein. Renare TV, uppvärmning för någon, chips start. <a href="#">Antioxidanter</a> eller om barnen orienterade, fotboll framför datorn. Medlemmar i dörren var intakt protein. Läxor fotbollstips lejon kartong bananer. Smartphones och bananer temperatur.</p>
    </section>
    <section id="tab-2" class="o-tab-panel">
        <h2>Tabbarna</h2>
        <p>Ta färdväg åker rot häst se precis det blev därmed se, <a href="#">söka smultron</a> för ingalunda brunsås fram se vi miljoner jäst olika, groda sällan dunge när tiden fram helt sig dock. För sax blivit redan av där vid upprätthållande omfångsrik det på bra, icke dunge på mjuka groda ser del kan stora. År denna gör erfarenheter häst bland tre ta söka redan år, dimma om händer rot dimma att om själv av sjö, sig stig genom och sorgliga själv verkligen nya där.</p>
    </section>
    <section id="tab-3" class="o-tab-panel">
        <h2> Går till elva</h2>
        <p>Gamla det som mjuka gamla hans gamla bra sista fram gamla, tiden trevnadens se hwila när själv nu har kanske hwila, helt i när groda göras rännil verkligen tid så. Dock upprätthållande ta faktor sällan dimmhöljd ingalunda mjuka, vidsträckt bra tidigare vemod samma att lax redan, bra oss strand dimma redan är. Räv att dimmhöljd söka kunde tiden söka vid när, gör del dag söka vad icke se, göras tidigare vid nu dunge kunde tiden.</p>
    </section>
    <section id="tab-4" class="o-tab-panel">
        <h2><svg width="20" height="20" viewbox="0 0 32 32">
                <path d="M31.5 18.2v-4.4h-4.7c-.3-1.4-.8-2.6-1.5-3.7l3.3-3.3-3.1-3.1L22.2 7c-1.2-.8-2.6-1.4-4-1.7V.5h-4.4v4.7c-1.4.2-2.7.8-3.9 1.6L6.7 3.6 3.6 6.7l3.2 3.2c-.8 1.2-1.3 2.5-1.6 3.9H.5v4.4h4.7c.3 1.5.9 2.8 1.7 4l-3.3 3.3 3.1 3.1 3.3-3.3c1.1.7 2.4 1.3 3.7 1.5v4.7h4.4v-4.7c1.4-.3 2.7-.8 3.9-1.6l3.4 3.4 3.1-3.1-3.4-3.4c.8-1.2 1.3-2.5 1.6-3.9h4.8zM16 23.5c-4.1 0-7.5-3.4-7.5-7.5s3.4-7.5 7.5-7.5 7.5 3.4 7.5 7.5-3.4 7.5-7.5 7.5z"></path>
            </svg></h2>
        <p>Dock upprätthållande ta faktor sällan dimmhöljd ingalunda mjuka, vidsträckt bra tidigare vemod samma att lax redan, bra oss strand dimma redan är. Räv att dimmhöljd söka kunde tiden söka vid när, gör del dag söka vad icke se, göras tidigare vid nu dunge kunde tiden. Gamla det som mjuka gamla hans gamla bra sista fram gamla, tiden trevnadens se hwila när själv nu har kanske hwila, helt i när groda göras rännil verkligen tid så. </p>
    </section>
</div>
<div data-tab-component>
		{{#if wrapped}}<div class="wrapper">{{/if}}
		<ul class="o-tab-list js-o-tab-list"{{#if updateURL}} data-update-url="true"{{/if}}>
			{{#each tab_item}}
				<li class="o-tab-list__item">
					<a class="o-tab-list__link" href="#{{id}}" id="tab-{{name}}">{{{heading}}}</a>
				</li>
			{{/each}}
		</ul>
	{{#if wrapped}}</div>{{/if}}
	{{#each tab_item}}
	<section id="{{id}}" class="o-tab-panel">
		<h2>{{{heading}}}</h2>
		{{#if content}}
			{{{content}}}
		{{/if}}
	</section>
	{{/each}}
</div>
{
  "updateURL": false,
  "tab_item": [
    {
      "id": "tab-1",
      "name": "namn-1",
      "heading": "De här",
      "content": "<p>Klinisk och min drink. Reserverad potten var nu en kund, men inte bara protein. Renare TV, uppvärmning för någon, chips start. <a href=\"#\">Antioxidanter</a> eller om barnen orienterade, fotboll framför datorn. Medlemmar i dörren var intakt protein. Läxor fotbollstips lejon kartong bananer. Smartphones och bananer temperatur.</p>"
    },
    {
      "id": "tab-2",
      "name": "namn-2",
      "heading": "Tabbarna",
      "content": "<p>Ta färdväg åker rot häst se precis det blev därmed se, <a href=\"#\">söka smultron</a> för ingalunda brunsås fram se vi miljoner jäst olika, groda sällan dunge när tiden fram helt sig dock. För sax blivit redan av där vid upprätthållande omfångsrik det på bra, icke dunge på mjuka groda ser del kan stora. År denna gör erfarenheter häst bland tre ta söka redan år, dimma om händer rot dimma att om själv av sjö, sig stig genom och sorgliga själv verkligen nya där.</p>"
    },
    {
      "id": "tab-3",
      "name": "namn-3",
      "heading": " Går till elva",
      "content": "<p>Gamla det som mjuka gamla hans gamla bra sista fram gamla, tiden trevnadens se hwila när själv nu har kanske hwila, helt i när groda göras rännil verkligen tid så. Dock upprätthållande ta faktor sällan dimmhöljd ingalunda mjuka, vidsträckt bra tidigare vemod samma att lax redan, bra oss strand dimma redan är. Räv att dimmhöljd söka kunde tiden söka vid när, gör del dag söka vad icke se, göras tidigare vid nu dunge kunde tiden.</p>"
    },
    {
      "id": "tab-4",
      "name": "namn-4",
      "heading": "<svg width=\"20\" height=\"20\" viewbox=\"0 0 32 32\"><path d=\"M31.5 18.2v-4.4h-4.7c-.3-1.4-.8-2.6-1.5-3.7l3.3-3.3-3.1-3.1L22.2 7c-1.2-.8-2.6-1.4-4-1.7V.5h-4.4v4.7c-1.4.2-2.7.8-3.9 1.6L6.7 3.6 3.6 6.7l3.2 3.2c-.8 1.2-1.3 2.5-1.6 3.9H.5v4.4h4.7c.3 1.5.9 2.8 1.7 4l-3.3 3.3 3.1 3.1 3.3-3.3c1.1.7 2.4 1.3 3.7 1.5v4.7h4.4v-4.7c1.4-.3 2.7-.8 3.9-1.6l3.4 3.4 3.1-3.1-3.4-3.4c.8-1.2 1.3-2.5 1.6-3.9h4.8zM16 23.5c-4.1 0-7.5-3.4-7.5-7.5s3.4-7.5 7.5-7.5 7.5 3.4 7.5 7.5-3.4 7.5-7.5 7.5z\"></path></svg>",
      "content": "<p>Dock upprätthållande ta faktor sällan dimmhöljd ingalunda mjuka, vidsträckt bra tidigare vemod samma att lax redan, bra oss strand dimma redan är. Räv att dimmhöljd söka kunde tiden söka vid när, gör del dag söka vad icke se, göras tidigare vid nu dunge kunde tiden. Gamla det som mjuka gamla hans gamla bra sista fram gamla, tiden trevnadens se hwila när själv nu har kanske hwila, helt i när groda göras rännil verkligen tid så. </p>"
    }
  ]
}
  • Content:
    @charset 'UTF-8';
    
    @include organism(tab-list) {
    	overflow: hidden;
    	display: flex;
    	position: relative;
    	margin: 0;
    	padding: 0;
    	overflow: auto;
    
    	&::-webkit-scrollbar {
    		position: absolute;
    		z-index: 2;
    		bottom: 0;
    		left: 0;
    		height: rhythm(0.5);
    	}
    
    	&::-webkit-scrollbar-track {
    		background-color: $color-ash;
    	}
    
    	&::-webkit-scrollbar-thumb {
    		background-color: $color-granit;
    	}
    
    	&::before {
    		@extend %u-visuallyhidden;
    
    		content: $namespace;
    	}
    
    	&::after {
    		content: '';
    		display: block;
    		position: fixed;
    		top: 0;
    		right: 0;
    		bottom: 0;
    		width: rhythm(3);
    		background: linear-gradient(90deg, rgba(237, 237, 237, 0) 0%, rgba(237, 237, 237, 1) 75%, rgba(237, 237, 237, 1) 100%);
    	}
    
    
    	@include e(item) {
    		display: flex;
    		flex: 0 0 auto;
    		padding: 0;
    
    		+ li {
    			margin-left: rhythm(1);
    		}
    	}
    
    	@include e(link) {
    		@extend %normalize-links;
    
    		display: inline-flex;
    		position: relative;
    		align-items: center;
    		padding: rhythm(1.5) rhythm(3);
    		border-top-left-radius: $border-radius;
    		border-top-right-radius: $border-radius;
    		background-color: $color-concrete;
    		color: $color-cyberspace;
    		text-decoration: none;
    
    		&:hover,
    		&:focus {
    			border-top-left-radius: $border-radius;
    			border-top-right-radius: $border-radius;
    		}
    
    		&:hover {
    			background-color: darken($color-concrete, 5%);
    		}
    	}
    
    	[data-tab-active] {
    		a {
    			background-color: $color-snow;
    		}
    	}
    }
    
    @include organism(tab-panel) {
    	position: relative;
    	z-index: 2;
    	padding: rhythm(2) rhythm(3);
    	border-top-right-radius: $border-radius;
    	border-bottom-right-radius: $border-radius;
    	border-bottom-left-radius: $border-radius;
    	background-color: $color-snow;
    
    	&[aria-hidden='true'] {
    		display: none;
    	}
    
    	&:focus {
    		outline: 0;
    	}
    }
    
    .no-js {
    	@include organism(tab-list) {
    		display: block;
    		padding: initial;
    		margin: initial;
    		list-style-type: disc;
    
    		@include plumber(
    			$leading-bottom: 3
    		);
    
    		@include e(item) {
    			display: list-item;
    			margin-top: rhythm(1);
    			margin-left: rhythm(4);
    			padding-top: rhythm(0.25);
    			padding-bottom: rhythm(0.25);
    			padding-top: 0;
    			padding-left: 0;
    		}
    
    		@include e(link) {
    			background-color: transparent;
    			padding: 0;
    			border-radius: 0;
    
    			@extend %link-styles;
    		}
    	}
    
    	@include organism(tab-panel) {
    		background-color: transparent;
    		padding: 0;
    	}
    }
    
  • URL: /components/raw/tabs/_tabs.scss
  • Filesystem Path: src/organisms/tabs/_tabs.scss
  • Size: 2.3 KB
  • Content:
    window.a11yTabs = (function tabsComponentIIFE(global, document) {
    	const tabInstances = new WeakMap();
    	const className = 'o-tab-list';
    	const tablistElement = document.querySelector(`.js-${className}`);
    	let updateURLFromHash;
    
    	if (tablistElement) {
    		updateURLFromHash = tablistElement.getAttribute('data-update-url');
    	}
    
    	/**
    	* Instantiates the component
    	* @constructor
    	* @param {DOM Node} element
    	*/
    	const TabComponent = function TabComponent(element, options) {
    		if (!element || !element.nodeType) {
    			return;
    		}
    
    		const namespace = getComputedStyle(tablistElement, ':before').content.replace(/["']/g, '');
    
    		const defaults = {
    			tabList: `.${namespace}${className}`,
    			tabItem: `.${namespace}${className}__item`,
    			tabLink: `.${namespace}${className}__link`,
    			tabPanel: `.${namespace}o-tab-panel`,
    		};
    
    		this.options = Object.assign(defaults, options);
    
    		this.element = element;
    		this.tabList = element.querySelector(this.options.tabList);
    		this.tabItems = [].slice.call(
    			this.tabList.querySelectorAll(this.options.tabItem),
    		);
    		this.tabLinks = [].slice.call(
    			this.tabList.querySelectorAll(this.options.tabLink),
    		);
    		this.tabPanels = [].slice.call(
    			element.querySelectorAll(this.options.tabPanel),
    		);
    
    		this.currentIndex = 0;
    
    		this.tabList.setAttribute('role', 'tablist');
    
    		this.tabItems.forEach((item, index) => {
    			item.setAttribute('role', 'presentation');
    
    			if (index === 0) {
    				item.setAttribute('data-tab-active', '');
    			}
    		});
    
    		this.tabLinks.forEach((item, index) => {
    			item.setAttribute('role', 'tab');
    
    			if (index > 0) {
    				item.setAttribute('tabindex', '-1');
    			} else {
    				item.setAttribute('aria-selected', 'true');
    			}
    		});
    
    		this.tabPanels.forEach((item, index) => {
    			item.setAttribute('role', 'tabpanel');
    			item.setAttribute('aria-labelledby', `tab${index}`);
    			item.setAttribute('tabindex', '-1');
    
    			if (index > 0) {
    				item.setAttribute('hidden', '');
    			}
    		});
    
    		this.eventCallback = handleEvents.bind(this); // eslint-disable-line
    		this.tabList.addEventListener('click', this.eventCallback, false);
    		this.tabList.addEventListener('keydown', this.eventCallback, false);
    
    		tabInstances.set(this.element, this);
    
    		// Select the correct tab based on URL hash
    		if (updateURLFromHash) {
    			this.selectTabFromHash();
    		}
    	};
    
    	TabComponent.prototype = {
    		/**
    		* Event handler for all tab interactions
    		* @param {number} index - Index of the tab being activiated
    		* @param {string} direction -
    		*/
    		handleTabInteraction: function handleTabInteraction(index, direction) {
    			const { currentIndex } = this;
    			let newIndex = index;
    
    			// The click event does not pass in a direction. This is for keyboard support
    			if (direction) {
    				if (direction === 37) {
    					newIndex = index - 1;
    				} else {
    					newIndex = index + 1;
    				}
    			}
    
    			// Supports continuous tabbing when reaching beginning or end of tab list
    			if (newIndex < 0) {
    				newIndex = this.tabLinks.length - 1;
    			} else if (newIndex === this.tabLinks.length) {
    				newIndex = 0;
    			}
    
    			// update tabs
    			this.tabLinks[currentIndex].setAttribute('tabindex', '-1');
    			this.tabLinks[currentIndex].removeAttribute('aria-selected');
    			this.tabItems[currentIndex].removeAttribute('data-tab-active');
    
    			this.tabLinks[newIndex].setAttribute('aria-selected', 'true');
    			this.tabItems[newIndex].setAttribute('data-tab-active', '');
    			this.tabLinks[newIndex].removeAttribute('tabindex');
    			this.tabLinks[newIndex].focus(); // Focus the newly selected tab
    
    			// update tab panels
    			this.tabPanels[currentIndex].setAttribute('hidden', '');
    			this.tabPanels[newIndex].removeAttribute('hidden');
    
    			// Update the browser's URL hash to reflect the current tab's ID
    			const selectedTabId = this.tabLinks[newIndex].id;
    
    			if (updateURLFromHash) {
    				window.history.pushState(null, '', `#${selectedTabId}`);
    			}
    
    			this.currentIndex = newIndex;
    
    			return this;
    		},
    
    		/**
    		* Set tab panel focus
    		* @param {number} index - Tab panel index to receive focus
    		*/
    		handleTabpanelFocus: function handleTabPanelFocus(index) {
    			this.tabPanels[index].focus();
    
    			return this;
    		},
    		/**
    		 * Selects a tab based on the URL hash
    		 */
    		selectTabFromHash() {
    			const { hash } = global.location;
    			if (hash) {
    				const targetId = hash.substring(1); // Remove the '#' character
    				const targetIndex = this.tabLinks.findIndex((link) => link.id === targetId);
    				if (targetIndex !== -1) {
    					this.handleTabInteraction(targetIndex);
    				}
    			}
    		},
    	};
    
    	/**
    	* Creates or returns existing component
    	* @param {string} selector
    	*/
    	function createTabComponent(selector, options) {
    		const elements = document.querySelectorAll(selector);
    		[].forEach.call(elements, (element) => tabInstances.get(element)
    		|| new TabComponent(element, options));
    	}
    
    	/**
    	* Destroys an existing component
    	* @param {DOM Node} element
    	*/
    	function destroyTabComponent(element) {
    		if (!element || !element.nodeType) {
    			return;
    		}
    
    		const component = tabInstances.get(element);
    		component.tabList.removeAttribute('role', 'tablist');
    
    		component.tabItems.forEach((item, index) => {
    			item.removeAttribute('role', 'presentation');
    
    			if (index === 0) {
    				item.removeAttribute('data-tab-active');
    			}
    		});
    
    		component.tabLinks.forEach((item, index) => {
    			item.removeAttribute('role', 'tab');
    			item.removeAttribute('id', `tab${index}`);
    
    			if (index > 0) {
    				item.removeAttribute('tabindex', '-1');
    			} else {
    				item.removeAttribute('aria-selected', 'true');
    			}
    		});
    
    		component.tabPanels.forEach((item, index) => {
    			item.removeAttribute('role', 'tabpanel');
    			item.removeAttribute('aria-labelledby', `tab${index}`);
    			item.removeAttribute('tabindex', '-1');
    
    			if (index > 0) {
    				item.removeAttribute('hidden');
    			}
    		});
    
    		component.tabList.removeEventListener('click', component.eventCallback);
    		component.tabList.removeEventListener('keydown', component.eventCallback);
    		tabInstances.delete(component.element);
    	}
    
    	/**
    	* Handles all event listener callbacks
    	* @param {event} event
    	*/
    	function handleEvents(event) {
    		if (event.type === 'click') {
    			event.preventDefault();
    			TabComponent.prototype.handleTabInteraction.call(
    				this,
    				this.tabLinks.indexOf(event.target),
    			);
    		}
    
    		if (event.type === 'keydown') {
    			const index = this.tabLinks.indexOf(event.target);
    
    			// Left and right arrows
    			if (event.which === 37 || event.which === 39) {
    				event.preventDefault();
    				TabComponent.prototype.handleTabInteraction.call(
    					this,
    					index,
    					event.which,
    				);
    			}
    
    			// Down arrow
    			if (event.which === 40) {
    				event.preventDefault();
    				TabComponent.prototype.handleTabpanelFocus.call(this, index);
    			}
    		}
    	}
    
    	return {
    		create: createTabComponent,
    		destroy: destroyTabComponent,
    	};
    }(window, document));
    
    const tabComponent = a11yTabs.create('[data-tab-component]'); // eslint-disable-line
    
  • URL: /components/raw/tabs/tabs.js
  • Filesystem Path: src/organisms/tabs/tabs.js
  • Size: 6.9 KB

No notes defined.