Responsive Full Width Tabs

100% width tabbed content with some example media queries for smaller screens.

A full width tab component with some example media queries for adjusting the icons of the tabs and the content layout. The main idea is to show only icons for the mobile view and allow the text to appear when there’s enough space. The content columns and the containing media boxes have three different layouts.

The food shapes in the content images are from PsdBlast. The icons used in the tabs are by DesignModo and the icon font was created using the Icomoon App.

The HTML

<div id="tabs" class="tabs">
	<nav>
		<ul>
			<li><a href="#section-1" class="icon-shop"><span>Shop</span></a></li>
			<li><a href="#section-2" class="icon-cup"><span>Drinks</span></a></li>
			<li><a href="#section-3" class="icon-food"><span>Food</span></a></li>
			<li><a href="#section-4" class="icon-lab"><span>Lab</span></a></li>
			<li><a href="#section-5" class="icon-truck"><span>Order</span></a></li>
		</ul>
	</nav>
	<div class="content">
		<section id="section-1">
			<div class="mediabox">
				<img src="img/01.png" alt="img01" />
				<h3>Sushi Gumbo Beetroot</h3>
				<p>Sushi gumbo beet greens corn soko endive gumbo gourd. Parsley shallot courgette tatsoi pea sprouts fava bean collard greens dandelion okra wakame tomato.</p>
			</div>
			<div class="mediabox">
				<img src="img/02.png" alt="img02" />
				<h3>Pea Sprouts Fava Soup</h3>
				<p>Lotus root water spinach fennel kombu maize bamboo shoot green bean swiss chard seakale pumpkin onion chickpea gram corn pea.</p>
			</div>
			<div class="mediabox">
				<img src="img/03.png" alt="img03" />
				<h3>Turnip Broccoli Sashimi</h3>
				<p>Nori grape silver beet broccoli kombu beet greens fava bean potato quandong celery. Bunya nuts black-eyed pea prairie turnip leek lentil turnip greens parsnip.</p>
			</div>
		</section>
		<section id="section-2">
			<div class="mediabox">
				<img src="img/04.png" alt="img04" />
				<h3>Asparagus Cucumber Cake</h3>
				<p>Chickweed okra pea winter purslane coriander yarrow sweet pepper radish garlic brussels sprout groundnut summer purslane earthnut pea tomato spring onion azuki bean gourd. </p>
			</div>
			<div class="mediabox">
				<img src="img/05.png" alt="img05" />
				<h3>Magis Kohlrabi Gourd</h3>
				<p>Salsify taro catsear garlic gram celery bitterleaf wattle seed collard greens nori. Grape wattle seed kombu beetroot horseradish carrot squash brussels sprout chard.</p>
			</div>
			<div class="mediabox">
				<img src="img/06.png" alt="img06" />
				<h3>Ricebean Rutabaga</h3>
				<p>Celery quandong swiss chard chicory earthnut pea potato. Salsify taro catsear garlic gram celery bitterleaf wattle seed collard greens nori. </p>
			</div>
		</section>
		<section id="section-3">
			<div class="mediabox">
				<img src="img/02.png" alt="img02" />
				<h3>Noodle Curry</h3>
				<p>Lotus root water spinach fennel kombu maize bamboo shoot green bean swiss chard seakale pumpkin onion chickpea gram corn pea.Sushi gumbo beet greens corn soko endive gumbo gourd.</p>
			</div>
			<div class="mediabox">
				<img src="img/06.png" alt="img06" />
				<h3>Leek Wasabi</h3>
				<p>Sushi gumbo beet greens corn soko endive gumbo gourd. Parsley shallot courgette tatsoi pea sprouts fava bean collard greens dandelion okra wakame tomato.</p>
			</div>
			<div class="mediabox">
				<img src="img/01.png" alt="img01" />
				<h3>Green Tofu Wrap</h3>
				<p>Pea horseradish azuki bean lettuce avocado asparagus okra. Kohlrabi radish okra azuki bean corn fava bean mustard tigernut wasabi tofu broccoli mixture soup.</p>
			</div>
		</section>
		<section id="section-4">
			<div class="mediabox">
				<img src="img/03.png" alt="img03" />
				<h3>Tomato Cucumber Curd</h3>
				<p>Chickweed okra pea winter purslane coriander yarrow sweet pepper radish garlic brussels sprout groundnut summer purslane earthnut pea tomato spring onion azuki bean gourd. </p>
			</div>
			<div class="mediabox">
				<img src="img/01.png" alt="img01" />
				<h3>Mushroom Green</h3>
				<p>Salsify taro catsear garlic gram celery bitterleaf wattle seed collard greens nori. Grape wattle seed kombu beetroot horseradish carrot squash brussels sprout chard.</p>
			</div>
			<div class="mediabox">
				<img src="img/04.png" alt="img04" />
				<h3>Swiss Celery Chard</h3>
				<p>Celery quandong swiss chard chicory earthnut pea potato. Salsify taro catsear garlic gram celery bitterleaf wattle seed collard greens nori. </p>
			</div>
		</section>
		<section id="section-5">
			<div class="mediabox">
				<img src="img/02.png" alt="img02" />
				<h3>Radish Tomato</h3>
				<p>Catsear cauliflower garbanzo yarrow salsify chicory garlic bell pepper napa cabbage lettuce tomato kale arugula melon sierra leone bologi rutabaga tigernut.</p>
			</div>
			<div class="mediabox">
				<img src="img/06.png" alt="img06" />
				<h3>Fennel Wasabi</h3>
				<p>Sea lettuce gumbo grape kale kombu cauliflower salsify kohlrabi okra sea lettuce broccoli celery lotus root carrot winter purslane turnip greens garlic.</p>
			</div>
			<div class="mediabox">
				<img src="img/01.png" alt="img01" />
				<h3>Red Tofu Wrap</h3>
				<p>Green horseradish azuki bean lettuce avocado asparagus okra. Kohlrabi radish okra azuki bean corn fava bean mustard tigernut wasabi tofu broccoli mixture soup.</p>
			</div>
		</section>
	</div><!-- /content -->
</div><!-- /tabs -->
<script src="js/cbpFWTabs.js"></script>
<script>
	new CBPFWTabs( document.getElementById( 'tabs' ) );
</script>

The CSS

@font-face {
	font-family: 'icomoon';
	src:url('../fonts/icomoon/icomoon.eot?pvm5gj');
	src:url('../fonts/icomoon/icomoon.eot?#iefixpvm5gj') format('embedded-opentype'),
		url('../fonts/icomoon/icomoon.woff?pvm5gj') format('woff'),
		url('../fonts/icomoon/icomoon.ttf?pvm5gj') format('truetype'),
		url('../fonts/icomoon/icomoon.svg?pvm5gj#icomoon') format('svg');
	font-weight: normal;
	font-style: normal;
} /* Icons created with icomoon.io/app */

.tabs {
	position: relative;
	width: 100%;
	overflow: hidden;
	margin: 1em 0 2em;
	font-weight: 300;
}

/* Nav */
.tabs nav {
	text-align: center;
}

.tabs nav ul {
	padding: 0;
	margin: 0;
	list-style: none;
	display: inline-block;
}

.tabs nav ul li {
	border: 1px solid #becbd2;
	border-bottom: none;
	margin: 0 0.25em;
	display: block;
	float: left;
	position: relative;
}

.tabs nav li.tab-current {
	border: 1px solid #47a3da;
	box-shadow: inset 0 2px #47a3da;
	border-bottom: none;
	z-index: 100;
}

.tabs nav li.tab-current:before,
.tabs nav li.tab-current:after {
	content: '';
	position: absolute;
	height: 1px;
	right: 100%;
	bottom: 0;
	width: 1000px;
	background: #47a3da;
}

.tabs nav li.tab-current:after {
	right: auto;
	left: 100%;
	width: 4000px;
}

.tabs nav a {
	color: #becbd2;
	display: block;
	font-size: 1.45em;
	line-height: 2.5;
	padding: 0 1.25em;
	white-space: nowrap;
}

.tabs nav a:hover {
	color: #768e9d;
}

.tabs nav li.tab-current a {
	color: #47a3da;
}

/* Icons */
.tabs nav a:before {
	display: inline-block;
	vertical-align: middle;
	text-transform: none;
	font-weight: normal;
	font-variant: normal;
	font-family: 'icomoon';
	line-height: 1;
	speak: none;
	-webkit-font-smoothing: antialiased;
	margin: -0.25em 0.4em 0 0;
}

.icon-food:before {
	content: "e600";
}

.icon-lab:before {
	content: "e601";
}

.icon-cup:before {
	content: "e602";
}

.icon-truck:before {
	content: "e603";
}

.icon-shop:before {
	content: "e604";
}

/* Content */
.content section {
	font-size: 1.25em;
	padding: 3em 1em;
	display: none;
	max-width: 1230px;
	margin: 0 auto;
}

.content section:before,
.content section:after {
	content: '';
	display: table;
}

.content section:after {
	clear: both;
}

/* Fallback example */
.no-js .content section {
	display: block;
	padding-bottom: 2em;
	border-bottom: 1px solid #47a3da;
}

.content section.content-current {
	display: block;
}

.mediabox {
	float: left;
	width: 33%;
	padding: 0 25px;
}

.mediabox img {
	max-width: 100%;
	display: block;
	margin: 0 auto;
}

.mediabox h3 {
	margin: 0.75em 0 0.5em;
}

.mediabox p {
	padding: 0 0 1em 0;
	margin: 0;
	line-height: 1.3;
}

/* Example media queries */

@media screen and (max-width: 52.375em) {
	.tabs nav a span {
		display: none;
	}

	.tabs nav a:before {
		margin-right: 0;
	}

	.mediabox {
		float: none;
		width: auto;
		padding: 0 0 35px 0;
		font-size: 90%;
	}

	.mediabox img {
		float: left;
		margin: 0 25px 10px 0;
		max-width: 40%;
	}

	.mediabox h3 {
		margin-top: 0;
	}

	.mediabox p {
		margin-left: 40%;
		margin-left: calc(40% + 25px);
	}

	.mediabox:before,
	.mediabox:after {
		content: '';
		display: table;
	}

	.mediabox:after {
		clear: both;
	}
}

@media screen and (max-width: 32em) {
	.tabs nav ul,
	.tabs nav ul li a {
		width: 100%;
		padding: 0;
	}

	.tabs nav ul li {
		width: 20%;
		width: calc(20% + 1px);
		margin: 0 0 0 -1px;
	}

	.tabs nav ul li:last-child {
		border-right: none;
	}

	.mediabox {
		text-align: center;
	}

	.mediabox img {
		float: none;
		margin: 0 auto;
		max-width: 100%;
	}

	.mediabox h3 {
		margin: 1.25em 0 1em;
	}

	.mediabox p {
		margin: 0;
	}
}

The JavaScript

/**
 * cbpFWTabs.js v1.0.0
 * http://www.codrops.com
 *
 * Licensed under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 * 
 * Copyright 2014, Codrops
 * http://www.codrops.com
 */
;( function( window ) {
	
	'use strict';

	function extend( a, b ) {
		for( var key in b ) { 
			if( b.hasOwnProperty( key ) ) {
				a[key] = b[key];
			}
		}
		return a;
	}

	function CBPFWTabs( el, options ) {
		this.el = el;
		this.options = extend( {}, this.options );
  		extend( this.options, options );
  		this._init();
	}

	CBPFWTabs.prototype.options = {
		start : 0
	};

	CBPFWTabs.prototype._init = function() {
		// tabs elemes
		this.tabs = [].slice.call( this.el.querySelectorAll( 'nav > ul > li' ) );
		// content items
		this.items = [].slice.call( this.el.querySelectorAll( '.content > section' ) );
		// current index
		this.current = -1;
		// show current content item
		this._show();
		// init events
		this._initEvents();
	};

	CBPFWTabs.prototype._initEvents = function() {
		var self = this;
		this.tabs.forEach( function( tab, idx ) {
			tab.addEventListener( 'click', function( ev ) {
				ev.preventDefault();
				self._show( idx );
			} );
		} );
	};

	CBPFWTabs.prototype._show = function( idx ) {
		if( this.current >= 0 ) {
			this.tabs[ this.current ].className = '';
			this.items[ this.current ].className = '';
		}
		// change current
		this.current = idx != undefined ? idx : this.options.start >= 0 && this.options.start < this.items.length ? this.options.start : 0;
		this.tabs[ this.current ].className = 'tab-current';
		this.items[ this.current ].className = 'content-current';
	};

	// add to global namespace
	window.CBPFWTabs = CBPFWTabs;

})( window );

Tagged with:

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay up to date with the latest web design and development news and relevant updates from Codrops.

Feedback 103

Comments are closed.
  1. This is simple, sleek and slick Flat design. I wished there was a way to “fade out and fade in” the different tab sections upon selection. Any Ideas?

    • I was wondering the same thing! Is there a way to adjust the javascript to allow it to fade in / out?

  2. Awesomely simple! I’m planning to use this for a microsite and have a question. If I want to open tab 2 or 3 from a text link inside the body content of tab one, how can I do that? I tried using their respective IDs but it doesn’t work. Basically, I want to cross link every tab via images and text links. Any help?

    • here you can crack this issue:

      CBPFWTabs.prototype.options = {
      start : 2 /* give here number and that tab will open */
      };

  3. Hi!! it’s a gorgeous effect! But i have a question, if I need to insert this gallery into two different section in my web site, how can I do it? thanks a lot!

  4. Mary, this script is awesome! I have some questions or favor (perhaps a better word for it 😉 ) for you :

    1. I am planning to use the icons on top right (prev , next etc) for “about”, “privacy policy” links, how can I show the content below the tabs without having a tab selected (if you already have an active tab) ?

    2. I would like to integrate your “tooltip menu” to be used in this script for the tabs when hovering , can you please share the code for this?

    Thanks for a great script once again and hope you can solve/answer my questions

  5. Forgot the last question:

    3. The previous asked question regarding linking to other tabs/content you answered :

    CBPFWTabs.prototype.options = {
    start : 2 /* give here number and that tab will open */
    };

    How do I implement this in a ?

    • Hi, Amelia,
      did you solve this?

      I’d like to link from extern to a tab, too.
      e.g. my-website.com/index.html#tab3

      any ideas? anyone???
      thanks in advance.

  6. aah , yet another question and that is :

    4. How to import icon set from Icomoon app, I have created my own set but I only have options of json, svg etc. and do not get the content in your folders, for instance in the bpicons folder :

    bpicons.eot
    bpicons.svg
    bpicons.ttf
    bpicons.woff

    I dont mind using the same font as you , all I want to do is change the icons and text (and that is made in the html file of course).

  7. Hi all.. one question, i can’t seem to click the tabs in IE. What’s the problem?

  8. Doesn’t support IE8, I am using the same concept for my site but there is no IE8 support, It says ‘Jscript object expected’ In your .js at line 37, I find it difficult to understand the problem. Please if you could help.
    Thank you.

  9. Is there a way I use these tabs more than once? Every time I try to use it again, it does’t work and it doesn’t show the content in the divs… please help!

  10. Great Script very simple and elegant .. but what if I want to change the color of active tab for each tab?

  11. Manh…which designing tools do you use…?…simply awesome design concepts…

  12. I see a problem with the tabs. The border bottom blue line doesn’t take full width when last tab selected.

    Steps to reproduce:

    1. Enter Full Screen mode in your browser.
    2. Try click Firs tab and the last tab.

    • Thanks for your feedback! This can be fixed by setting the width of the :before pseudo-element of the tab anchor to a much higher number, i.e.

      .tabs nav li.tab-current:before, .tabs nav li.tab-current:after {
      content: '';
      position: absolute;
      height: 1px;
      right: 100%;
      bottom: 0;
      width: 4000px;
      background: #47a3da;
      }
      
  13. Awesome example, Mary Lou!

    How would you make it so that the tabs are vertically aligned for larger size devices and then horizontally aligned for smaller devices (as is)?

    Thanks!

  14. Will this work with multiple tabs on the same screen, if you change the initializing script from:

    new CBPFWTabs( document.getElementById( ‘tabs’ ) );

    to:

    new CBPFWTabs(document.getElementsByClassName( ‘tabs’ ) );

  15. How can I change tabs to keep always visible when scrolling on mobile browsers? I want to keep the tabs as a menu always visible.

  16. Hi Mary, its really awesome n i am using it, but I am having a problem:

    Please tell me how to link the tabs with href or some similar way with hyperlinks on the same page or some other page.

  17. Hi Moderator.

    Is my last comment deleted by you? If yes, may I know why.
    I had asked Mary that how to link the tabs with hyperlinks on the same page or some other page.

    Please let the question through as the jquery is of no use without hyperlinking them.

    • Hi Amandeep, obviously we didn’t delete your comment, but since the moderators are human beings they occasionally have to sleep 🙂

  18. Hi MARY LOU,

    How can I add more tabs without affecting the responsiveness when using smaller screens? When I add more tabs, they jump to the next line on various devices and smaller screens.

    Thanks

    • Hi LeoVertu

      Here’s what work for me.
      To keep the tabs (actually tab icons) on the same line on a small screen you have to adjust the size of each in the component.css inside the following section:
      @media screen and (max-width: 32em) { .tabs nav ul, .tabs nav ul li a { width: 100%; padding: 0; } .tabs nav ul li { width: 20%; width: calc(20% + 1px); margin: 0 0 0 -1px; } .tabs nav ul li:last-child { border-right: none; } }
      What I did to fix this issue was to simply adjust the width from 20% to a lower values until all tabs could fit in one line (in my case, 7 tabs on 4.5in phone screen).

  19. Awesome plugin…
    One question though….
    Can we center the content if we are using one “Mediabox”… need help… Thanks a lot…

  20. hello

    while loading the tab section i also need to call another javascript funtion.

    pls help

    Thanks

  21. Dear Mary Lou,

    Thanks for cool stuff. But, how about compability in IE browser?
    When I run in Chrome or Mozilla, it’s seem well, but not in IE.

  22. Any chance somebody knows how to edit the js so that it doesn’t remove pre-existing classes on the tabbed elements?

    • One way to do it:
      include the classie.js (https://github.com/desandro/classie) script, or any other similar script, and change the _show method to:
      CBPFWTabs.prototype._show = function( idx ) { if( this.current >= 0 ) { classie.remove(this.tabs[ this.current ], 'tab-current'); classie.remove(this.items[ this.current ], 'content-current'); } // change current this.current = idx != undefined ? idx : this.options.start >= 0 && this.options.start < this.items.length ? this.options.start : 0; classie.add(this.tabs[ this.current ], 'tab-current'); classie.add(this.items[ this.current ], 'content-current'); };

  23. I have used this to great effect at http://www.megsphotos.co.uk on the portfolio page.

    My question like many others remains unanswered… how do I place a ‘next tab’ link on each section?

    So far I have had to put a link that goes back to the top of the page so the user can click the next tab…. this is less than ideal :/

  24. Hi all,
    please i want to maintain the same active tab after postback.
    how ???

    please helppppppppppp

    • Thanks to Pedro Botelho:

      var triggers = [].slice.call( tabs.querySelectorAll( ‘nav > ul > li’ ) );
      document.getElementById(‘linkToOtherTab’).addEventListener(‘click’, function() {
      triggers[1].click(); // this would open the “second” tab
      });

      You can change tabs by calling

      triggers[x].click();

      where x is the number of the tab you want activating

    • i forgot! add this id in htlm:

      then the Pedro code become:
      var triggers = [].slice.call( tabs.querySelectorAll( ‘nav > ul > li’ ) );
      document.getElementById(‘firstab’).addEventListener(‘click’, function() {
      });
      triggers[x].click(); // change x with the tab you want open

  25. Hey great demo. As always.

    But hey I was wondering how would you can a touch effect to slide between tabs on mobile?

    • Well, use your imagination 😉

      Fitting wide navigation into narrow screen is a problem with no obvious or best solution. This article showcases one idea. If you have a different layout and purpose, then think differently. The first idea that comes to mind is to stack navigation items on top of each other similar to way the paragraphs in the demo are being stacked.

  26. Hi everyone!
    I don’t think I’ve seen my question answered…
    What I want to do:
    Open the url where my tabs are in from another page, but forcing it to show a specific tab…

    for example: I’m in page1.html where there’s a link called “toTab3”. I want that link to get me to page2.html, where I have 4 tabs, showing the 3rd one.

    Makes sense?…. thanks in advance!

    • This is a common task but goes beyond the purposes of the demo which is to demonstrate an idea of a responsive tabbed nav.

      All you need to do is to set a class “active” (in this case “tab-current”) to the navigation item that you want highlighted as active. But how you do it depends on your website setup. One way is to set the back-end code appropriately, another is to use named anchor tags (http://www.w3.org/TR/html401/struct/links.html#h-12.2.1) along with javascript to check window.location.hash of the document and apply the active class to the corresponding navigation item.

    • I used these tabs on a site for a client and they were amazed by them!

      If you or anyone else is still looking for a way to force open a certain tab from a different page, here is my solution.

      Put a # and a number from 0 to how many tabs you have after the links to certain tabs.
      For example: i have 4 tabs and 4 links, one for each tab. I put #0, #1, #2, #3 after each link in order to open a specific tab.
      <a href="link-to-tab-1.php#0">tab 1</a> <a href="link-to-tab-2.php#1">tab 2</a> <a href="link-to-tab-3.php#2">tab 3</a> <a href="link-to-tab-4.php#3">tab 4</a>

      The js code needs some slight modifications as well.
      var x = window.location.hash; var last = x.slice(-1); CBPFWTabs.prototype.options = { start : last };

      Add the two lines of code above the prototype.options. The first line sets the variable x with the content from the URL after and including the #. The second line of code slices away just the last character of the link, in my case the numbers from 0 to 3.

      The start : last then sets the starting position tab according to the link pressed and voila, the tabs open accordingly to the pressed links.

      My tabs can be visible here uhy.si

  27. I’m trying to figure out how embed a youtube video inside of the media box, but I’m running into some problems.
    What are the best practices for this specific template?
    I haven’t been able to get the video to appear and I was wondering if you had any recommendations?

  28. The last 2 tabs in the demo do not extend the full width when in desktop mode.
    The left blue underline stops short from the browser edge…

    How do I go about fixing this?

  29. i using the Third tab when i reload the page the current tab will come once again to initial position of the tab

    example :

    in third tab current section have a textbox and other controls in a submit click the page reload in that situation it come to the First Tab

    Please Resolve it Say the way to rectify it

  30. Hi Mary Lou, Great script !! I have recently used this script on http://www.inspiredcreditmanagement.com.au and I was wondering if you know of a fix so that when viewing on desktop if you click a tab it takes you back to the top of that section? At present clicking any tab takes you to the scroll position/location within the next tab (if that makes sense). To test simply scroll to the bottom of the first tab and then click the second tab. Any ideas/solutions would be super appreciated 🙂 Cheers, Phil.

  31. Hi,
    This works well but not in IE8 there is this error IE throws i tried modify .js but doesnt work still? can you pls check the .js,

    Message: JScript object expected
    Line: 37
    Char: 3
    Code: 0
    URI: file:///C:/ProjectTasks/FullWidthTabs/FullWidthTabs/cbpFWTabs.js

    thanks,

  32. HI
    This was work very well and great use full on my site.
    but i want fade effect on show item how to fix this one please reply as soon as possible.

  33. Not working on IE8, due to this “Array.prototype.slice: ‘this’ is not a JavaScript object”

    CBPFWTabs.prototype._init = function() {
    // tabs elemes
    this.tabs = [].slice.call( this.el.querySelectorAll( ‘nav > ul > li’ ) )
    [error]Array.prototype.slice: ‘this’ is not a JavaScript object[error]
    // content items
    this.items = [].slice.call( this.el.querySelectorAll( ‘.content > section’ ) );

  34. This is awesome.
    What solution would you use to solve uneven columns if I wanted to use more than 3 items per section? Right now the next item gets shoved to the right side because the right column (3rd item) is shorter. I tried to simply wrap the 3 columns in a div but that did not solve it. the div gets ignored (not entirely sure why). See example: http://jeffreyjamesmusic.com/hotcity-preliminary/