Ever wanted to have a Tab Pane without having to use a pile of Javascript?

Well this tabbed pane is pure CSS, and can be used via keyboard or mouse.

It is known to be compatible with IE9, Firfox 3.6+, Opera 11, Chrome and Safari.

First off the tab needs to:
  • Be backed by something.
  • Be keyboard navigable.
  • Retain state when focus is lost.
  • Only allow one item to be selected at a time.
  • Be Styled like a tab.
Radio inputs and labels are perfect for this...

		<input type="radio" name="tabGroup1" id="rad1" class="tab1" checked="checked"/>
		<input type="radio" name="tabGroup1" id="rad2" class="tab2"/>
		<input type="radio" name="tabGroup1" id="rad3" class="tab3"/>
		
		<div class="tablabels">
			<label for="rad1">Introduction</label><br/>
			<label for="rad2">So how's it done?</label><br/>
			<label for="rad3">View the source</label>
		</div>

Note:

  • The radio inputs are at the outer root level of the html, this is important for the css matching rules.
  • The radio id and the label id match thus binding them together.
  • The first radio only is checked, as this is the default tab to show.
  • The radio name 'tabGroup1', this allows only one item to be selected in a radio group at a time.
  • It has a class of tab1, this is used later to match the tab to its content.

Doesn't this leave an ugly radio on the screen?
Yes, so why not just move it off-screen...

			.tabGroup > input[type="radio"] {
				position: absolute;
				left:0px;
				top:-100px;
			}

Now we need a content pane.
This is just a basic div.

...

		<div class="tablabels">
			<div class="tab1">Some content</div>
			<div class="tab2">Some more content</div>
			<div class="tab3">Even more content</div>
		</div>

Note how the div has a class of "tab1", this exactly matches the class on the radio.
We add the following CSS to hide/show it when the associated radio is selected.

		.tabGroup > .div.tabcontent > div {
			display: none;
		}
		
		.tabGroup > .tab1:checked ~ div.tabcontent > .tab1,
		.tabGroup > .tab2:checked ~ div.tabcontent > .tab2,
		.tabGroup > .tab3:checked ~ div.tabcontent > .tab3 {
			display: inline-block;
		}

This source code is free and has no warranty.
Do whatever you want with it, except copy this tutorial to your website and say you wrote it!

Cheers, [email protected]

HTML:
			<div class="tabGroup">
				<input type="radio" name="tabGroup1" id="rad1" class="tab1" checked="checked"/>
				<input type="radio" name="tabGroup1" id="rad2" class="tab2"/>
				<input type="radio" name="tabGroup1" id="rad3" class="tab3"/>
				
				<div class="tablabels">
					<label for="rad1">Tab 1</label>
					<label for="rad2">Tab 2</label>
					<label for="rad3">Tab 3</label>
				</div>

				<div class="tabcontent">
					<div class="tab1">Tab 1 content</div>
					<div class="tab2">Tab 2 content</div>
					<div class="tab3">Tab 3 content</div>
				</div>
			</div>
		

CSS:
			/* Set the size and font of the tab widget */
			.tabGroup {
				font: 10pt arial, verdana;
				width: 960px;
			}

			/* Configure the radio buttons to hide off screen */
			.tabGroup > input[type="radio"] {
				position: absolute;
				left:-100px;
			}

			/* Configure maximum width of tabs and align to top */
			.tabGroup > div.tablabels {
				display: inline-block;
				vertical-align: top;
				width:160px;
				margin-right:17px;
			}

			/* Configure labels to look like tabs */
			.tabGroup > div.tablabels > label {
				/* inline-block such that the label can be given dimensions */
				display: inline-block;
				width:100%;
				
				/* A nice curved border around the tab */
				border: 1px solid black;
				border-radius: 5px 0 0 5px;
				-moz-border-radius: 5px 0 0 5px ;
				-webkit-border-radius: 5px 0 0 5px ;

				/* Padding around tab text */
				padding: 5px 10px;

				/* Set the background color to default gray (non-selected tab) */
				background-color:#ddd;
				
				z-index:32767;
			}

			/* Focused tabs need to be highlighted as such */
			.tabGroup > input#rad1:focus ~ div.tablabels > label[for="rad1"],
			.tabGroup > input#rad2:focus ~ div.tablabels > label[for="rad2"],
			.tabGroup > input#rad3:focus ~ div.tablabels > label[for="rad3"] {
				border:1px dashed black;
			}

			/* Checked tabs must be white with the bottom border removed */
			.tabGroup > input#rad1:checked ~ div.tablabels > label[for="rad1"],
			.tabGroup > input#rad2:checked ~ div.tablabels > label[for="rad2"],
			.tabGroup > input#rad3:checked ~ div.tablabels > label[for="rad3"] {
				background-color:white;
				font-weight: bold;
				border-right: 1px solid white;
				position:relative;
			}

			.tabGroup > div.tabcontent {
				display: inline-block;
				height: 400px;
			}

			/* The tab content must fill the widgets size and have a nice border */
			.tabGroup > div.tabcontent > div {
				width:720px;
				display: none;
				border: 1px solid black;
				background-color: white;
				padding: 10px 10px;
				height: 100%;
				overflow: auto;
				
				box-shadow: 0 0 20px #444;
				-moz-box-shadow: 0 0 20px #444;
				-webkit-box-shadow: 0 0 20px #444;
				
				border-radius: 0 5px 5px 5px;
				-moz-border-radius: 0 5px 5px 5px;
				-webkit-border-radius: 0 5px 5px 5px;
			}

			/* This matchs tabs displaying to thier associated radio inputs */
			.tabGroup > .tab1:checked ~ div.tabcontent > .tab1,
			.tabGroup > .tab2:checked ~ div.tabcontent > .tab2,
			.tabGroup > .tab3:checked ~ div.tabcontent > .tab3 {
				display: inline-block;
			}