Giter Site home page Giter Site logo

cferdinandi / tabby Goto Github PK

View Code? Open in Web Editor NEW
590.0 18.0 72.0 828 KB

Lightweight, accessible vanilla JS toggle tabs.

License: MIT License

JavaScript 53.19% CSS 12.38% HTML 34.43%
javascript vanilla-js javascript-plugin tabs toggle-tabs no-dependencies

tabby's Introduction

Tabby Build Status

Lightweight, accessible vanilla JS toggle tabs.

View the Demo on CodePen β†’

Getting Started | Styling | Keyboard Navigation | API | What's New | Browser Compatibility | License


Want to learn how to write your own vanilla JS plugins? Check out my Vanilla JS Pocket Guides or join the Vanilla JS Academy and level-up as a web developer. πŸš€


Getting Started

Compiled and production-ready code can be found in the dist directory. The src directory contains development code.

1. Include Tabby on your site.

There are two versions of Tabby: the standalone version, and one that comes preloaded with polyfills for the closest() and matches() methods, which are only supported in newer browsers.

If you're including your own polyfills, use the standalone version. Otherwise, use the version with polyfills.

Tabby also comes with two simple themes/UIs. Feel free to start with one of them and modify it for your needs, or start from scratch and build your own.

Direct Download

You can download the files directly from GitHub.

<link rel="stylesheet" type="text/css" href="path/to/tabby.min.css">
<script src="path/to/tabby.polyfills.min.js"></script>

CDN

You can also use the jsDelivr CDN. I recommend linking to a specific version number or version range to prevent major updates from breaking your site. Tabby uses semantic versioning.

<!-- Always get the latest version -->
<!-- Not recommended for production sites! -->
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/cferdinandi/tabby/dist/css/tabby-ui.min.css">
<script src="https://cdn.jsdelivr.net/gh/cferdinandi/tabby/dist/js/tabby.polyfills.min.js"></script>

<!-- Get minor updates and patch fixes within a major version -->
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/cferdinandi/tabby@12/dist/css/tabby-ui.min.css">
<script src="https://cdn.jsdelivr.net/gh/cferdinandi/tabby@12/dist/js/tabby.polyfills.min.js"></script>

<!-- Get patch fixes within a minor version -->
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/cferdinandi/[email protected]/dist/css/tabby-ui.min.css">
<script src="https://cdn.jsdelivr.net/gh/cferdinandi/[email protected]/dist/js/tabby.polyfills.min.js"></script>

<!-- Get a specific version -->
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/cferdinandi/[email protected]/dist/css/tabby-ui.min.css">
<script src="https://cdn.jsdelivr.net/gh/cferdinandi/[email protected]/dist/js/tabby.polyfills.min.js"></script>

NPM

You can also use NPM (or your favorite package manager).

npm install tabbyjs

2. Add the markup to your HTML.

Tabby progressively enhances a linked list of content into tabbed navigation.

Provide an unordered list of content, with anchor links that point to your content. Give your tab navigation a selector you can target. In this example, it's [data-tabs], but it can be anything you want.

Add the [data-tabby-default] attribute to the tab that should be displayed by default.

<ul data-tabs>
	<li><a data-tabby-default href="#harry">Harry Potter</a></li>
	<li><a href="#hermione">Hermione</a></li>
	<li><a href="#neville">Neville</a></li>
</ul>

<div id="harry">...</div>
<div id="hermione">...</div>
<div id="neville">...</div>

Note: Tabby automatically adds all of the required roles, attributes, and keyboard interactions needed for proper accessibility.

3. Initialize Tabby.

In the footer of your page, after the content, initialize Tabby by passing in a selector for the navigation menu. And that's it, you're done. Nice work!

<script>
	var tabs = new Tabby('[data-tabs]');
</script>

Styling Tabby

Tabby comes with two simple themes/UIs: standard horizontal tabs, and vertical ones. Use them as-is, modify them to meet your needs, or skip them entirely and build your own from scratch.

Horizontal UI on CodePen β†’ | Veritical UI on CodePen β†’ | No UI on CodePen β†’

Note: the vertical tab layout does not include a grid. You'll need to supply your own.

You can use the role attributes that are added to the elements to progressively style them.

  • The list (<ul></ul>) has the [role="tablist"] attribute.
  • Tab links (<a href="#anchor"></a>) have the [role="tab"] attribute.
  • Active tab links have the [aria-selected="true"] attribute.
  • Tab content has the [role="tabpanel"] attribute.
  • Hidden tab content has the [hidden] attribute.

Keyboard Navigation

Tabby follows accessibility recommendations and expectations for keyboard navigation:

  • Arrow keys (left/right and up/down) change the active tab in the navigation.
  • The Home and End buttons activate the first and last tab, respectively.
  • The Tab key shifts focus into the tab content rather than to the next item in the navigation.

API

Tabby includes smart defaults and works right out of the box. But if you want to customize things, it also has a robust API that provides multiple ways for you to adjust the default options and settings.

Options and Settings

You can pass options and callbacks into Tabby when instantiating.

var tabs = new Tabby('[data-tabs]', {
	idPrefix: 'tabby-toggle_', // The prefix to add to tab element IDs if they don't already have one
	default: '[data-tabby-default]' // The selector to use for the default tab
});

Custom Events

Tabby emits a custom eventβ€”tabbyβ€”when the active tab is changed.

The tabby event is emitted on the tab element and bubbles up. You can listen for them with the addEventListener() method. The event.detail object includes the previousTab, previousContent, tab and content elements.

document.addEventListener('tabby', function (event) {
	var tab = event.target;
	var content = event.detail.content;
}, false);

Methods

Tabby also exposes several public methods.

setup()

Sets up the DOM with the required roles and attributes. If you dynamically add navigation items to the DOM after Tabby is instantiated, you can run this method to set them up.

Example

var tabs = new Tabby('data-tabs');
tabs.setup();

toggle()

Activate a tab. Accepts the ID of the content to activate, or a tab element, as an argument.

Example

var tabs = new Tabby('data-tabs');

// With a selector
tabs.toggle('#harry');

// With an element
var neville = document.querySelector('[href*="#neville"]');
tabs.toggle(neville);

destroy()

Destroy the current initialization.

Example

var tabs = new Tabby('data-tabs');
tabs.destroy();

What's new?

Tabby got a complete rewrite in version 12. It now includes:

  • Support for multiple instantiations at once.
  • Proper roles and properties for accessibility.
  • Keyboard navigation
  • Deprecated callbacks in favor of custom events.

Migrating to Tabby 12 from Older Versions

The instantiation method is completely different, but the markup patterns in older versions should work without modification.

Kudos πŸ‘

Special thanks to Dave Rupers A11y Nutrition Cards, which provided a solid foundation for this version.

And major kudos to accessibility specialist Scott O'Hara, who advised me on various aspects of this script throughout its development.

Browser Compatibility

Tabby works in all modern browsers, and IE 9 and above.

Tabby is built with modern JavaScript APIs, and uses progressive enhancement. If the JavaScript file fails to load, or if your site is viewed on older and less capable browsers, anchor links will jump to the content instead.

Polyfills

Support back to IE9 requires polyfills for the closest() and matches(). Without them, support will be spotty across browsers.

Use the included polyfills version of Tabby, or include your own.

[hidden]

Tabby uses the [hidden] attribute to hide tab content. This attribute didn't exist prior to IE11. To push support back to IE9, make sure your stylesheet includes the following style for the [hidden] attribute.

[hidden] {
	display: none;
}

License

The code is available under the MIT License.

tabby's People

Contributors

cferdinandi avatar jaukia avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tabby's Issues

Hash URLs

Have you thought about using hash URLs so users can link to a specific tab?

Unable to view canvas when switching back to its tab

I'm using Chart.js to display data and it uses <canvas> to display that data. My charts are in the initial tab of my app but when looking at another tab for a couple minutes, the charts disappear when going back to their tab.

I'd like to prevent this from happening. In my research, it appears that the canvas "forgets" what its dimensions are when the parent container is hidden. Is there some sort of fix I can apply to tabby to make my charts appear as normal?

Docs incomplete

I copy pasted the example from the docs "List Links". It gives:

Uncaught TypeError: Cannot read property 'parentNode' of undefined

The example is missing the two last tabs-pane.

Update semantics

Source: https://24ways.org/2015/how-tabs-should-work/

  • All content is navigable and available without JavaScript.
  • The tabs are anchor links that:
    • are clickable
    • have block layout
    • have their href pointing to the id of the panel element
    • use the correct cursor (i.e. cursor: pointer).
  • Since tabs are clickable, the user can open in a new tab/window and the page correctly loads with the correct tab open.
  • Right-clicking (and Shift-clicking) doesn’t cause the tab to be selected.
  • Native browser Back/Forward button correctly changes the state of the selected tab (think about it working exactly as if there were no JavaScript in place).

Add optimize js

package.json

"gulp-optimize-js": "^1.0.2",

gulpfile.js

var optimizejs = require('gulp-optimize-js');

    var jsTasks = lazypipe()
        .pipe(header, banner.full, { package : package })
        .pipe(optimizejs)
        .pipe(gulp.dest, paths.scripts.output)
        .pipe(rename, { suffix: '.min' })
        .pipe(uglify)
        .pipe(optimizejs)
        .pipe(header, banner.min, { package : package })
        .pipe(gulp.dest, paths.scripts.output);

Get rid of unused var

var collapses = document.querySelectorAll(collapseID); // Get collapse content

in toggleTab

Page scrolls when click active tab

Clicking on each tabs is fine, and changes the pane accordingly. I just don't like it when clicking the tab when its active, scrolls the page to the pane. Possible that an option can be created to disable this? This can be tested by going to the demo http://cferdinandi.github.io/tabby/#tabb and making the height of the browser < 330.

Switch tab makes the page jump

I'm using Tabby 11.2.0 and have no other javascripts. The only CSS I have is display: block and display: none. Maybe it's the hash?

tabby

Hiding browser tooltips for hash urls

Thanks for the excellent library!

I wonder if there is a way to hide the browser hover tooltips when using tabby, maybe by using something else that hash urls for navigation. Especially in mobile-like footer navigation, the flashing tooltips are more annoying than useful.

screen shot 2016-03-30 at 14 28 16
screen shot 2016-03-30 at 14 29 15

1 Navi 2 Tabs

Hi there againe cferdinandi.

my last problem worked out after your fix. Thanks for that againe. But now i got a question regarding multible tabs thats being controled by 1 navigation. First i just tried if it's possible at all... result the first Tab changes like it should. The second Tab area works fine on adding the calss to show the Tab. But it dosnt remove from the previous active one the style to hide it.

I know, #ID's arent meant to use more then once on a page but... i needed to try anyways. Do you know what i can change to get this working? Since adding works fine but removing not.

Room for animations

Hey, I thought I could add an example in tabby's documentation how to add some simple animations, like fade out/in, but I'm not sure how to switch to a new tab with delay, so I can fade out the previous pane before fading in the next one.

Browser History

Anyway to implement keeping the deep linking but stop the browser keeping the history of the tabs being opened?

Combining tabby with a Shop CMS

Hi there,

I am rly happy with tabby so far. My Static sites work pretty well with it. But i have a question.
I am currently trying to add tabby into a Shop CMS called "ShopWare"... it wen pretty well so far. The Javascript is loaded the css also. But somehow... chrome says me there is an error wich i dont get...

Uncaught TypeError: Cannot read property 'classList' of null
(anonymous function) @ tabby.js:232
forEach @ tabby.js:58
hideOtherTabs @ tabby.js:229
tabby.toggleTab @ tabby.js:279
eventHandler @ tabby.js:294

i never changed something in the js. The only thing thats diffrent then usual is thats on a cms, the arel that is loaded gets another css style after 7 second via js timeout command. and the execusen of tabby.init(); is delayed by 8 seconds.

I dont know what to do. Tabby is kinda my last hope on my template. Hope someone has any idea what i can do to get that fiex. If you need any files to understand how it it's build just ask.

Can i create multible tabs and use hash url to navigate?

Can i create multible tabs and use hash url to navigate?
Hello, sorry for my english. I can use a hash url, to navigate through multiple tabs at once?
For example I have 3 categories, and each category has sub-item.
Each category is a tab. Each item is a tab.
How do I get there using hash url in point 5 of the second category

tabby.toggleTab() prevents from clicking previous active tab

Title says it all :)

Steps to reproduce using the Unstructured list tabs:

  1. Go to http://cferdinandi.github.io/tabby
  2. In the Unstructured list click on Seasons
  3. Tab now changes to seasons
  4. Open the Console
  5. Execute the code tabby.toggleTab('#tab2')
  6. The page now shows

Ice Cream

Chocolate, vanilla or strawberry?
  1. Click on the Seasons tab
  2. Nothing happens
  3. Click on Superheroes
  4. This works
  5. Click on Seasons tab
  6. Now this works as well

Unexpected token ( - SyntaxError

I got the following error while using tabby.

Uncaught SyntaxError: Unexpected token ( 

I am including tabby using require.js with the following config:

  shim: {
    tabby: ['jquery']
  }

Possible to disable back/forward history of tabs.

I'm using tabby almost like a "toggle" on the page that a user might switch between tabs many times during a pageview. If they've done it 10+ times, using the back button becomes extremely tedious. Is there a way (option) to disable the back button history on tab changes?

All the title will be active if they have the same href.

for example:

<ul data-tabs class="tabs">
	<li><a data-tab href="#info">Basic info</a></li>
	<li><a data-tab href="#nopermission">Advantage info</a></li>
	<li><a data-tab href="#nopermission">Secret info</a></li>
</ul>

<div data-tabs-content>
	<div data-tabs-pane class="tabs-pane active" id="info">
		<p><strong>Superheros</strong></p>
		<p>Spiderman, Batman, or Iron Man... which one is your favorite?</p>
	</div>
	<div data-tabs-pane class="tabs-pane" id="nopermission">
		<p><strong>Ice Cream</strong></p>
		<p>Chocolate, vanilla or strawberry?</p>
	</div>
</div>

I have a panel, the last two tab link refer to the same tabs-pane. When I click the last two tab title( Advantage info and Secret info, both of them will be set active. Is there any convenient way that I can only set the tab title had been clicked active so that only one button will be highlighted?

'active' class being set to <a> tag

There is an active class being added to both the 'li' and the child 'a' tag on the tabs. When you select another tab the active class gets updated on the 'li' tag but stays on all the 'a' tags user clicks. Need to toggle classes on 'a' tag as well.

Thanks!

Update NPM deps and switch to lib-sass

package.json

"gulp": "^3.9.0",
"node-fs": "^0.1.7",
"del": "^1.2.0",
"lazypipe": "^0.2.4",
"gulp-plumber": "^1.0.1",
"gulp-flatten": "^0.0.4",
"gulp-tap": "^0.1.3",
"gulp-rename": "^1.2.2",
"gulp-header": "^1.2.2",
"gulp-footer": "^1.0.5",
"gulp-watch": "^4.2.4",
"gulp-livereload": "^3.8.0",
"gulp-jshint": "^1.11.1",
"jshint-stylish": "^2.0.1",
"gulp-concat": "^2.6.0",
"gulp-uglify": "^1.2.0",
"karma": "^0.12.37",
"gulp-karma": "^0.0.4",
"karma-coverage": "^0.4.2",
"jasmine": "^2.3.1",
"karma-jasmine": "^0.3.6",
"karma-phantomjs-launcher": "^0.2.0",
"karma-spec-reporter": "^0.0.19",
"karma-htmlfile-reporter": "^0.2.1",
"gulp-sass": "^2.0.3",
"gulp-minify-css": "^1.2.0",
"gulp-autoprefixer": "^2.3.1",
"gulp-svgmin": "^1.1.2",
"gulp-svgstore": "^5.0.2",
"gulp-markdown": "^1.0.0",
"gulp-file-include": "^0.11.1"

gulpfile.js

.pipe(sass({
    outputStyle: 'expanded',
    sourceComments: true
}))

a11y considerations

Two options for how to hide the content:

  1. Only hide it visually, but show it visually when a keyboard user tabs into it.
  2. Don't display it at all, and only show it when activated with JavaScript.

I'm leaning towards the first option.

smaller css

I'm not sure if this is a bug or not, but I just wanted to give back based on my use of the project.

Because I already have a normalize.css loaded, I was able to delete almost the entire css. The following leaves bit-exact perfectly functioning tabby.

.js-tabby .tabs-pane:focus {
    outline: none
}

.js-tabby .tabs-pane:not(.active) {
    display: none;
}

hope it helps

it's live on my site

a11y issues

  • Don't hide content, just visually mask it.
  • Bring active tab into focus

Disable hash?

I did not find how to disable using hash. Sometimes hash are good but sometimes not. I have many functions that could leave traces in the url but I prefer to keep things clean.

Is it possible in a simple way to not use hash in the url?

Toggle Tabby - Quick and dirty solution

I needed to be able to toggle when clicking on the same tab twice. I made a solution for it. In case someone needs the same thing, here it is:

document.addEventListener("DOMContentLoaded", function(event) {
	var tabby_active;
	tabby.init({
		callback: function ( tabs, toggle ) {
			var active_pane = document.querySelector('.tabs-pane.active');
			var active_tab = document.querySelector('.tabs .active');
			
			if( tabby_active == toggle ) {
				active_pane.classList.remove('active');
				active_tab.classList.remove('active');
				active_tab.querySelector('.active').classList.remove('active');
				tabby_active = '';
			} else {
				tabby_active = '#' + active_pane.getAttribute('id');
			}
		}
	});
});

Initialize specific tabs

I may be wrong, but it seems inconvenient that I can only initialize all tabs ever, not individually. Especially if I want to attach some options to certain tabs. This would loosen things up for users who are creating a .tabs component (which is often), without wanting tabby to initialize it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.