3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
4 This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6 The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7 Code distributed by Google as part of the polymer project is also
8 subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
11 <link rel=
"import" href=
"../polymer/polymer.html">
12 <link rel=
"import" href=
"../iron-flex-layout/iron-flex-layout.html">
13 <link rel=
"import" href=
"../iron-flex-layout/classes/iron-flex-layout.html">
14 <link rel=
"import" href=
"../iron-resizable-behavior/iron-resizable-behavior.html">
15 <link rel=
"import" href=
"../iron-menu-behavior/iron-menubar-behavior.html">
16 <link rel=
"import" href=
"../iron-icon/iron-icon.html">
17 <link rel=
"import" href=
"../paper-icon-button/paper-icon-button.html">
18 <link rel=
"import" href=
"../paper-styles/color.html">
19 <link rel=
"import" href=
"paper-tabs-icons.html">
20 <link rel=
"import" href=
"paper-tab.html">
23 `paper-tabs` makes it easy to explore and switch between different views or functional aspects of
24 an app, or to browse categorized data sets.
26 Use `selected` property to get or set the selected tab.
30 <paper-tabs selected="0">
31 <paper-tab>TAB 1</paper-tab>
32 <paper-tab>TAB 2</paper-tab>
33 <paper-tab>TAB 3</paper-tab>
36 See <a href="#paper-tab">paper-tab</a> for more information about
39 A common usage for `paper-tabs` is to use it along with `iron-pages` to switch
40 between different views.
42 <paper-tabs selected="{{selected}}">
43 <paper-tab>Tab 1</paper-tab>
44 <paper-tab>Tab 2</paper-tab>
45 <paper-tab>Tab 3</paper-tab>
48 <iron-pages selected="{{selected}}">
55 To use links in tabs, add `link` attribute to `paper-tab` and put an `<a>`
56 element in `paper-tab`.
60 <paper-tabs selected="0">
62 <a href="#link1" class="horizontal center-center layout">TAB ONE</a>
65 <a href="#link2" class="horizontal center-center layout">TAB TWO</a>
68 <a href="#link3" class="horizontal center-center layout">TAB THREE</a>
74 The following custom properties and mixins are available for styling:
76 Custom property | Description | Default
77 ----------------|-------------|----------
78 `--paper-tabs-selection-bar-color` | Color for the selection bar | `--paper-yellow-a100`
79 `--paper-tabs` | Mixin applied to the tabs | `{}`
85 <dom-module id=
"paper-tabs">
91 @apply(--layout-center);
97 -webkit-user-select: none;
98 -moz-user-select: none;
99 -ms-user-select: none;
101 -webkit-tap-highlight-color: rgba(
0,
0,
0,
0);
103 @apply(--paper-tabs);
117 #tabsContent.scrollable {
141 background-color: var(--paper-tabs-selection-bar-color, --paper-yellow-a100);
142 -webkit-transform-origin: left center;
143 transform-origin: left center;
144 -webkit-transform: scale(
0);
146 transition: -webkit-transform;
147 transition: transform;
149 @apply(--paper-tabs-selection-bar);
152 #selectionBar.align-bottom {
157 #selectionBar.expand {
158 transition-duration:
0.15s;
159 transition-timing-function: cubic-bezier(
0.4,
0.0,
1,
1);
162 #selectionBar.contract {
163 transition-duration:
0.18s;
164 transition-timing-function: cubic-bezier(
0.0,
0.0,
0.2,
1);
167 #tabsContent
> ::content
> *:not(#selectionBar) {
175 <paper-icon-button icon=
"paper-tabs:chevron-left" class$=
"[[_computeScrollButtonClass(_leftHidden, scrollable, hideScrollButtons)]]" on-up=
"_onScrollButtonUp" on-down=
"_onLeftScrollButtonDown"></paper-icon-button>
177 <div id=
"tabsContainer" class=
"flex" on-scroll=
"_scroll">
179 <div id=
"tabsContent" class$=
"[[_computeTabsContentClass(scrollable)]]">
181 <content select=
"*"></content>
183 <div id=
"selectionBar" class$=
"[[_computeSelectionBarClass(noBar, alignBottom)]]"
184 on-transitionend=
"_onBarTransitionEnd"></div>
190 <paper-icon-button icon=
"paper-tabs:chevron-right" class$=
"[[_computeScrollButtonClass(_rightHidden, scrollable, hideScrollButtons)]]" on-up=
"_onScrollButtonUp" on-down=
"_onRightScrollButtonDown"></paper-icon-button>
203 Polymer
.IronResizableBehavior
,
204 Polymer
.IronMenubarBehavior
210 * If true, ink ripple effect is disabled.
218 * If true, the bottom bar to indicate the selected tab will not be shown.
226 * If true, the slide effect for the bottom bar is disabled.
234 * If true, tabs are scrollable and the tab width is based on the label width.
242 * If true, dragging on the tabs to scroll is disabled.
250 * If true, scroll buttons (left/right arrow) will be hidden for scrollable tabs.
258 * If true, the tabs are aligned to bottom (the selection bar appears at the top).
266 * Gets or sets the selected element. The default is to use the index of the item.
308 'iron-resize': '_onResize',
309 'iron-select': '_onIronSelect',
310 'iron-deselect': '_onIronDeselect'
313 _computeScrollButtonClass: function(hideThisButton
, scrollable
, hideScrollButtons
) {
314 if (!scrollable
|| hideScrollButtons
) {
318 if (hideThisButton
) {
319 return 'not-visible';
325 _computeTabsContentClass: function(scrollable
) {
326 return scrollable
? 'scrollable' : 'horizontal layout';
329 _computeSelectionBarClass: function(noBar
, alignBottom
) {
332 } else if (alignBottom
) {
333 return 'align-bottom';
337 // TODO(cdata): Add `track` response back in when gesture lands.
339 _onResize: function() {
340 this.debounce('_onResize', function() {
342 this._tabChanged(this.selectedItem
);
346 _onIronSelect: function(event
) {
347 this._tabChanged(event
.detail
.item
, this._previousTab
);
348 this._previousTab
= event
.detail
.item
;
349 this.cancelDebouncer('tab-changed');
352 _onIronDeselect: function(event
) {
353 this.debounce('tab-changed', function() {
354 this._tabChanged(null, this._previousTab
);
355 // See polymer/polymer#1305
359 get _tabContainerScrollSize () {
362 this.$.tabsContainer
.scrollWidth
-
363 this.$.tabsContainer
.offsetWidth
367 _scroll: function() {
370 if (!this.scrollable
) {
374 scrollLeft
= this.$.tabsContainer
.scrollLeft
;
376 this._leftHidden
= scrollLeft
=== 0;
377 this._rightHidden
= scrollLeft
=== this._tabContainerScrollSize
;
380 _onLeftScrollButtonDown: function() {
381 this._holdJob
= setInterval(this._scrollToLeft
.bind(this), this._holdDelay
);
384 _onRightScrollButtonDown: function() {
385 this._holdJob
= setInterval(this._scrollToRight
.bind(this), this._holdDelay
);
388 _onScrollButtonUp: function() {
389 clearInterval(this._holdJob
);
390 this._holdJob
= null;
393 _scrollToLeft: function() {
394 this.$.tabsContainer
.scrollLeft
-= this._step
;
397 _scrollToRight: function() {
398 this.$.tabsContainer
.scrollLeft
+= this._step
;
401 _tabChanged: function(tab
, old
) {
403 this._positionBar(0, 0);
407 var r
= this.$.tabsContent
.getBoundingClientRect();
409 var tabRect
= tab
.getBoundingClientRect();
410 var tabOffsetLeft
= tabRect
.left
- r
.left
;
413 width
: this._calcPercent(tabRect
.width
, w
),
414 left
: this._calcPercent(tabOffsetLeft
, w
)
417 if (this.noSlide
|| old
== null) {
418 // position bar directly without animation
419 this._positionBar(this._pos
.width
, this._pos
.left
);
423 var oldRect
= old
.getBoundingClientRect();
424 var oldIndex
= this.items
.indexOf(old
);
425 var index
= this.items
.indexOf(tab
);
428 // bar animation: expand
429 this.$.selectionBar
.classList
.add('expand');
431 if (oldIndex
< index
) {
432 this._positionBar(this._calcPercent(tabRect
.left
+ tabRect
.width
- oldRect
.left
, w
) - m
,
435 this._positionBar(this._calcPercent(oldRect
.left
+ oldRect
.width
- tabRect
.left
, w
) - m
,
436 this._calcPercent(tabOffsetLeft
, w
) + m
);
439 if (this.scrollable
) {
440 this._scrollToSelectedIfNeeded(tabRect
.width
, tabOffsetLeft
);
444 _scrollToSelectedIfNeeded: function(tabWidth
, tabOffsetLeft
) {
445 var l
= tabOffsetLeft
- this.$.tabsContainer
.scrollLeft
;
447 this.$.tabsContainer
.scrollLeft
+= l
;
449 l
+= (tabWidth
- this.$.tabsContainer
.offsetWidth
);
451 this.$.tabsContainer
.scrollLeft
+= l
;
456 _calcPercent: function(w
, w0
) {
460 _positionBar: function(width
, left
) {
467 'translate3d(' + left
+ '%, 0, 0) scaleX(' + (width
/ 100) + ')',
468 this.$.selectionBar
);
471 _onBarTransitionEnd: function(e
) {
472 var cl
= this.$.selectionBar
.classList
;
473 // bar animation: expand -> contract
474 if (cl
.contains('expand')) {
477 this._positionBar(this._pos
.width
, this._pos
.left
);
478 // bar animation done
479 } else if (cl
.contains('contract')) {
480 cl
.remove('contract');