Tabs
Tabs are used to quickly navigate between views within the same context.
Underlined Tabs
<div class="container py-8 font-sans">
<div
x-data="{ ...tabs() }"
>
<ul
role="tablist"
class="z-10 flex items-end -mb-px border-b border-gray-300"
>
<li role="presentation" class="inline-flex">
<button
x-ref="tab-1"
id="tab-1"
x-bind:tabindex="tabIndex(1)"
x-bind:class="tabClasses(1)"
class="px-6 py-3 font-bold border-transparent border-b-3 hover:bg-gray-100 focus:outline-none focus:ring focus:ring-blue-500"
x-bind:aria-selected="isActiveTab(1)"
role="tab"
x-on:click.prevent="setActiveTab(1)"
x-on:keydown.arrow-left="null"
x-on:keydown.arrow-right="setActiveTab(2)"
>
Section 1
</button>
</li>
<li role="presentation" class="inline-flex">
<button
x-ref="tab-2"
id="tab-2"
x-bind:tabindex="tabIndex(2)"
x-bind:class="tabClasses(2)"
class="px-6 py-3 font-bold border-transparent border-b-3 hover:bg-gray-100 focus:outline-none focus:ring focus:ring-blue-500"
x-bind:aria-selected="isActiveTab(2)"
role="tab"
x-on:click.prevent="setActiveTab(2)"
x-on:keydown.arrow-left="setActiveTab(1)"
x-on:keydown.arrow-right="setActiveTab(3)"
>
Section 2
</button>
</li>
<li role="presentation" class="inline-flex">
<button
x-ref="tab-3"
id="tab-3"
x-bind:tabindex="tabIndex(3)"
x-bind:class="tabClasses(3)"
class="px-6 py-3 font-bold border-transparent border-b-3 hover:bg-gray-100 focus:outline-none focus:ring focus:ring-blue-500"
x-bind:aria-selected="isActiveTab(3)"
role="tab"
x-on:click.prevent="setActiveTab(3)"
x-on:keydown.arrow-left="setActiveTab(2)"
x-on:keydown.arrow-right="null"
>
Section 3
</button>
</li>
</ul>
<div>
<section
x-show="isActiveTab(1)"
id="section-1"
class="py-6"
aria-labelledby="tab-1"
x-bind:hidden="!isActiveTab(1)"
role="tabpanel"
>
Section 1 content Lorem ipsum dolor sit amet consectetur, adipisicing elit. Dignissimos qui soluta consequuntur dolore ipsa nemo voluptas eius nam quasi cumque. Labore vel quisquam, tempore officia pariatur aliquam sunt recusandae expedita!
</section>
<section
x-show="isActiveTab(2)"
id="section-2"
class="py-6"
aria-labelledby="tab-2"
x-bind:hidden="!isActiveTab(2)"
role="tabpanel"
>
Section 2 content Lorem ipsum dolor sit amet consectetur, adipisicing elit. Dignissimos qui soluta consequuntur dolore ipsa nemo voluptas eius nam quasi cumque. Labore vel quisquam, tempore officia pariatur aliquam sunt recusandae expedita! Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus sunt nemo quae assumenda mollitia, porro molestias odit at recusandae maiores nobis veniam cumque tempora perspiciatis vitae.
</section>
<section
x-show="isActiveTab(3)"
id="section-3"
class="py-6"
aria-labelledby="tab-3"
x-bind:hidden="!isActiveTab(3)"
role="tabpanel"
>
Section 3 content Lorem ipsum dolor sit amet consectetur, adipisicing elit. Dignissimos qui soluta consequuntur dolore ipsa nemo voluptas eius nam quasi cumque!
</section>
</div>
</div>
</div>
<script>
const tabs = () => {
return {
active: 1,
setActiveTab(index) {
this.active = index;
this.$refs['tab-' + index].focus();
},
isActiveTab(index) {
return this.active === index
},
tabClasses(index) {
return {
'border-red-600 text-gray-800': this.isActiveTab(index),
'text-gray-600': !this.isActiveTab(index)
}
},
tabIndex(index) {
return this.isActiveTab(index) ? '' : '-1'
}
}
}
</script>
Bordered Tabs
<div class="container py-8 font-sans">
<div
x-data="{ ...tabs() }"
>
<ul role="tablist" class="-mb-px z-10 flex items-end">
<li role="presentation" class="inline-flex">
<button
x-ref="tab-1"
id="tab-1"
x-bind:tabindex="tabIndex(1)"
x-bind:class="tabClasses(1)"
class="px-6 py-3 font-bold border-t border-l border-r border-transparent hover:border-gray-300 focus:outline-none focus:ring focus:ring-blue-500"
x-bind:aria-selected="isActiveTab(1)"
role="tab"
x-on:click.prevent="setActiveTab(1)"
x-on:keydown.arrow-left=""
x-on:keydown.arrow-right="setActiveTab(2)"
>
Section 1
</button>
</li>
<li role="presentation" class="inline-flex">
<button
x-ref="tab-2"
id="tab-2"
x-bind:tabindex="tabIndex(2)"
x-bind:class="tabClasses(2)"
class="px-6 py-3 font-bold border-t border-l border-r border-transparent hover:border-gray-300 focus:outline-none focus:ring focus:ring-blue-500"
x-bind:aria-selected="isActiveTab(2)"
role="tab"
x-on:click.prevent="setActiveTab(2)"
x-on:keydown.arrow-left="setActiveTab(1)"
x-on:keydown.arrow-right="setActiveTab(3)"
>
Section 2
</button>
</li>
<li role="presentation" class="inline-flex">
<button
x-ref="tab-3"
id="tab-3"
x-bind:tabindex="tabIndex(3)"
x-bind:class="tabClasses(3)"
class="px-6 py-3 font-bold border-t border-l border-r border-transparent hover:border-gray-300 focus:outline-none focus:ring focus:ring-blue-500"
x-bind:aria-selected="isActiveTab(3)"
role="tab"
x-on:click.prevent="setActiveTab(3)"
x-on:keydown.arrow-left="setActiveTab(2)"
x-on:keydown.arrow-right=""
>
Section 3
</button>
</li>
</ul>
<div class="border border-gray-300">
<section
x-show="isActiveTab(1)"
id="section-1"
class="px-4 py-6"
aria-labelledby="tab-1"
x-bind:hidden="!isActiveTab(1)"
role="tabpanel"
>
Section 1 content Lorem ipsum dolor sit amet consectetur, adipisicing elit. Dignissimos qui soluta consequuntur dolore ipsa nemo voluptas eius nam quasi cumque. Labore vel quisquam, tempore officia pariatur aliquam sunt recusandae expedita!
</section>
<section
x-show="isActiveTab(2)"
id="section-2"
class="px-4 py-6"
aria-labelledby="tab-2"
x-bind:hidden="!isActiveTab(2)"
role="tabpanel"
>
Section 2 content Lorem ipsum dolor sit amet consectetur, adipisicing elit. Dignissimos qui soluta consequuntur dolore ipsa nemo voluptas eius nam quasi cumque. Labore vel quisquam, tempore officia pariatur aliquam sunt recusandae expedita! Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus sunt nemo quae assumenda mollitia, porro molestias odit at recusandae maiores nobis veniam cumque tempora perspiciatis vitae.
</section>
<section
x-show="isActiveTab(3)"
id="section-3"
class="px-4 py-6"
aria-labelledby="tab-3"
x-bind:hidden="!isActiveTab(3)"
role="tabpanel"
>
Section 3 content Lorem ipsum dolor sit amet consectetur, adipisicing elit. Dignissimos qui soluta consequuntur dolore ipsa nemo voluptas eius nam quasi cumque!
</section>
</div>
</div>
</div>
<script>
const tabs = () => {
return {
active: 1,
setActiveTab(index) {
this.active = index;
this.$refs['tab-' + index].focus();
},
isActiveTab(index) {
return this.active === index
},
tabClasses(index) {
return {
'text-gray-800 bg-white border-gray-300': this.isActiveTab(index),
'text-gray-600 bg-transparent': !this.isActiveTab(index)
}
},
tabIndex(index) {
return this.isActiveTab(index) ? '' : '-1'
}
}
}
</script>
Detached Tabs
<div class="container py-8 font-sans">
<div
x-data="{ ...tabs() }"
class="mt-8"
>
<ul role="tablist" class="z-10 flex items-end space-x-12">
<li role="presentation" class="inline-flex">
<button
x-ref="tab-1"
id="tab-1"
x-bind:tabindex="tabIndex(1)"
x-bind:class="tabClasses(1)"
class="py-1 border-transparent border-b-2 transition-colors focus:outline-none focus:ring focus:ring-blue-500"
x-bind:aria-selected="isActiveTab(1)"
role="tab"
x-on:click.prevent="setActiveTab(1)"
x-on:keydown.arrow-left=""
x-on:keydown.arrow-right="setActiveTab(2)"
>
Fall 2020
</button>
</li>
<li role="presentation" class="inline-flex">
<button
x-ref="tab-2"
id="tab-2"
x-bind:tabindex="tabIndex(2)"
x-bind:class="tabClasses(2)"
class="py-1 border-transparent border-b-2 transition-colors focus:outline-none focus:ring focus:ring-blue-500"
x-bind:aria-selected="isActiveTab(2)"
role="tab"
x-on:click.prevent="setActiveTab(2)"
x-on:keydown.arrow-left="setActiveTab(1)"
x-on:keydown.arrow-right="setActiveTab(3)"
>
Winter 2020
</button>
</li>
<li role="presentation" class="inline-flex">
<button
x-ref="tab-3"
id="tab-3"
x-bind:tabindex="tabIndex(3)"
x-bind:class="tabClasses(3)"
class="py-1 border-transparent border-b-2 transition-colors focus:outline-none focus:ring focus:ring-blue-500"
x-bind:aria-selected="isActiveTab(3)"
role="tab"
x-on:click.prevent="setActiveTab(3)"
x-on:keydown.arrow-left="setActiveTab(2)"
x-on:keydown.arrow-right="setActiveTab(4)"
>
Spring 2021
</button>
</li>
<li role="presentation" class="inline-flex">
<button
x-ref="tab-4"
id="tab-4"
x-bind:tabindex="tabIndex(4)"
x-bind:class="tabClasses(4)"
class="py-1 border-transparent border-b-2 transition-colors focus:outline-none focus:ring focus:ring-blue-500"
x-bind:aria-selected="isActiveTab(4)"
role="tab"
x-on:click.prevent="setActiveTab(4)"
x-on:keydown.arrow-left="setActiveTab(3)"
x-on:keydown.arrow-right=""
>
Summer 2021
</button>
</li>
</ul>
<div>
<section
x-show="isActiveTab(1)"
id="section-1"
class="py-8 space-y-2"
aria-labelledby="tab-1"
x-bind:hidden="!isActiveTab(1)"
role="tabpanel"
>
<a href="#" class="block p-4 text-gray-700 border border-gray-600 transition-colors hover:bg-gray-100">
<h3 class="text-gray-900">ACES Peer Mentor</h3>
<p>(applications will be available in Fall 2020)</p>
</a>
<a href="#" class="block p-4 text-gray-700 border border-gray-600 transition-colors hover:bg-gray-100">
<h3 class="text-gray-900">ACES Peer Mentor</h3>
<p>(applications will be available in Fall 2020)</p>
</a>
<a href="#" class="block p-4 text-gray-700 border border-gray-600 transition-colors hover:bg-gray-100">
<h3 class="text-gray-900">ACES Peer Mentor</h3>
<p>(applications will be available in Fall 2020)</p>
</a>
<a href="#" class="block p-4 text-gray-700 border border-gray-600 transition-colors hover:bg-gray-100">
<h3 class="text-gray-900">ACES Peer Mentor</h3>
<p>(applications will be available in Fall 2020)</p>
</a>
</section>
<section
x-show="isActiveTab(2)"
id="section-2"
class="py-8 space-y-2"
aria-labelledby="tab-2"
x-bind:hidden="!isActiveTab(2)"
role="tabpanel"
>
<a href="#" class="block p-4 text-gray-700 border border-gray-600 transition-colors hover:bg-gray-100">
<h3 class="text-gray-900">ACES Peer Mentor</h3>
<p>(applications will be available in Winter 2020)</p>
</a>
<a href="#" class="block p-4 text-gray-700 border border-gray-600 transition-colors hover:bg-gray-100">
<h3 class="text-gray-900">ACES Peer Mentor</h3>
<p>(applications will be available in Winter 2020)</p>
</a>
<a href="#" class="block p-4 text-gray-700 border border-gray-600 transition-colors hover:bg-gray-100">
<h3 class="text-gray-900">ACES Peer Mentor</h3>
<p>(applications will be available in Winter 2020)</p>
</a>
<a href="#" class="block p-4 text-gray-700 border border-gray-600 transition-colors hover:bg-gray-100">
<h3 class="text-gray-900">ACES Peer Mentor</h3>
<p>(applications will be available in Winter 2020)</p>
</a>
</section>
<section
x-show="isActiveTab(3)"
id="section-3"
class="py-8 space-y-2"
aria-labelledby="tab-3"
x-bind:hidden="!isActiveTab(3)"
role="tabpanel"
>
<a href="#" class="block p-4 text-gray-700 border border-gray-600 transition-colors hover:bg-gray-100">
<h3 class="text-gray-900">ACES Peer Mentor</h3>
<p>(applications will be available in Spring 2021)</p>
</a>
<a href="#" class="block p-4 text-gray-700 border border-gray-600 transition-colors hover:bg-gray-100">
<h3 class="text-gray-900">ACES Peer Mentor</h3>
<p>(applications will be available in Spring 2021)</p>
</a>
<a href="#" class="block p-4 text-gray-700 border border-gray-600 transition-colors hover:bg-gray-100">
<h3 class="text-gray-900">ACES Peer Mentor</h3>
<p>(applications will be available in Spring 2021)</p>
</a>
<a href="#" class="block p-4 text-gray-700 border border-gray-600 transition-colors hover:bg-gray-100">
<h3 class="text-gray-900">ACES Peer Mentor</h3>
<p>(applications will be available in Spring 2021)</p>
</a>
</section>
<section
x-show="isActiveTab(4)"
id="section-4"
class="py-8 space-y-2"
aria-labelledby="tab-4"
x-bind:hidden="!isActiveTab(4)"
role="tabpanel"
>
<a href="#" class="block p-4 text-gray-700 border border-gray-600 transition-colors hover:bg-gray-100">
<h3 class="text-gray-900">ACES Peer Mentor</h3>
<p>(applications will be available in Summer 2021)</p>
</a>
<a href="#" class="block p-4 text-gray-700 border border-gray-600 transition-colors hover:bg-gray-100">
<h3 class="text-gray-900">ACES Peer Mentor</h3>
<p>(applications will be available in Summer 2021)</p>
</a>
<a href="#" class="block p-4 text-gray-700 border border-gray-600 transition-colors hover:bg-gray-100">
<h3 class="text-gray-900">ACES Peer Mentor</h3>
<p>(applications will be available in Summer 2021)</p>
</a>
<a href="#" class="block p-4 text-gray-700 border border-gray-600 transition-colors hover:bg-gray-100">
<h3 class="text-gray-900">ACES Peer Mentor</h3>
<p>(applications will be available in Summer 2021)</p>
</a>
</section>
</div>
</div>
</div>
<script>
const tabs = () => {
return {
active: 1,
setActiveTab(index) {
this.active = index;
this.$refs['tab-' + index].focus();
},
isActiveTab(index) {
return this.active === index
},
tabClasses(index) {
return {
'border-gray-900 text-gray-900': this.isActiveTab(index),
'text-gray-600 hover:border-gray-600': !this.isActiveTab(index)
}
},
tabIndex(index) {
return this.isActiveTab(index) ? '' : '-1'
}
}
}
</script>
Usage
Tabs are in-page navigation using a horizontal list of links (there should always be more than one). These links should bring you to another view of the page and the one selected should be highlighted for reference. The view below the tab should change to reflect the content of the chosen tab and should not navigate away from the original page.
Labels should be concise and there should be no more than six tabs total. Tabs with related content should be grouped together for best usability.
Use Cases
- When a user wants to compare between individual but related content (degree options, lab options, program options)
- When displaying a secondary navigation (program information with each tab being a different page under the same program)
- When displaying related but individual content that does not need to be compared (booking options and fees on a lab page)
- When in conjunction with carousels to add functionality to allow a user to cycle through content either using carousel indicators or tab headlines
Accessibility Requirements
Each tab should have a unique title that clearly describes the content. This is most helpful for those using assistive technologies so they have the necessary information to efficiently navigate the content. The developer should ensure that the content added to the tab panel follows the accessibility guidelines for the internal content.
It is recommended to use a <button>
element with the role tab for their built-in functional and accessible features instead, as opposed to needing to add them yourself. For controlling tab key functionality for elements with the role tab, it is recommended to set all non-active elements to tabindex=-1
, and to set the active element to tabindex=0
.
Tabs need to be optimized for mobile use to ensure that all of the tabs are visible and none of the text is being truncated.