Components chevron_right Tabs

Basic Usage

<PaperTabs @center={{this.center}} @stretch={{this.stretch}} @borderBottom={{this.borderBottom}} @selected={{this.selectedBasicTab}} @onChange={{action (mut this.selectedBasicTab)}} as |tabs|>
  <tabs.tab>
    Page One
  </tabs.tab>
  <tabs.tab @disabled={{true}}>
    Page Two (disabled)
  </tabs.tab>
  <tabs.tab>
    Page Three
  </tabs.tab>
  <tabs.tab>
    Page Four
  </tabs.tab>
  <tabs.tab>
    Page Five
  </tabs.tab>
</PaperTabs>

{{#liquid-bind (hash tab=this.selectedBasicTab) class="md-padding" as |current|}}
  <h1 class="md-display-2">Tab {{current.tab}}</h1>
  <p>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    Nulla venenatis ante augue. Phasellus volutpat neque ac dui mattis
    vulputate. Etiam consequat aliquam cursus. In sodales pretium ultrices.
    Maecenas lectus est, sollicitudin consectetur felis nec, feugiat ultricies mi.
  </p>
{{/liquid-bind}}
Page One
Page Two (disabled)
Page Three
Page Four
Page Five

Tab 0

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla venenatis ante augue. Phasellus volutpat neque ac dui mattis vulputate. Etiam consequat aliquam cursus. In sodales pretium ultrices. Maecenas lectus est, sollicitudin consectetur felis nec, feugiat ultricies mi.

Center tabs
Stretch tabs
Border bottom

Note: transitions were implemented using liquid-fire.

The way that we teach paper-tabs is that they are essentially a radio-group with some additional features (like tab pagination). So, this component essentially is just a tab header you can use to control a value of a property.

To reinforce this idea, each of the tabs optionally accepts a value property which needs to match the paper-tabs selected property (see API table below for more info). You don't need to use the value property, though. Each tab is automatically given a value equal to its index. So, your onChange action will start getting integer values if you don't specify any value on the tabs.

It is up to the user to manage the body of the tabs. They're free to use liquid-fire, css transitions or even just plain handlebars {{#if}}s. This makes the component much more flexible and DDAU-compliant, in our experience, but it also means you will need to do a little bit more work to manage what you want to do with the value. Thankfully Ember makes this dead easy for us.

To test tab pagination resize the browser.

Dynamic Usage

<PaperTabs @primary={{true}} @borderBottom={{true}} @selected={{this.selectedChapter}} @onChange={{action (mut this.selectedChapter)}} as |tabs|>
  {{#each this.chapters as |chapter|}}
    <tabs.tab @value={{chapter}}>
      {{chapter.title}}
    </tabs.tab>
  {{/each}}
</PaperTabs>

{{#liquid-bind (hash tab=this.selectedChapter.index m=this.selectedChapter) class="md-padding dynamic-animation" as |current|}}
  <h1 class="md-display-2">{{current.m.title}}</h1>
  <p>{{current.m.body}}</p>
  <PaperButton @primary={{true}} @raised={{true}} @disabled={{eq this.chapters.length 1}} @onClick={{action "removeChapter" current.m}}>
    Remove chapter
  </PaperButton>
{{/liquid-bind}}
Chapter 1
Chapter 2
Chapter 3
Chapter 4

Chapter 1

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla venenatis ante augue. Phasellus volutpat neque ac dui mattis vulputate. Etiam consequat aliquam cursus. In sodales pretium ultrices. Maecenas lectus est, sollicitudin consectetur felis nec, feugiat ultricies mi.

Note: transitions were implemented using liquid-fire.

In this example we render tabs dynamically, one per model. Note that we need some simple book-keeping to implement some specific features.

What happens when we delete an active chapter? We decide that by setting selected. When adding a new chapter we want it to be the new selected tab. No problem, just set the selected property to the newly selected chapter.

Routable Usage

<PaperTabs @selected={{this.router.currentRouteName}} @borderBottom={{true}} @onChange={{action "noop"}} as |tabs|>
  <tabs.tab @value="demo.tabs.index" @href={{href-to "demo.tabs.index"}}>
    Index
  </tabs.tab>
  <tabs.tab @value="demo.tabs.nested-route" @href={{href-to "demo.tabs.nested-route"}}>
    Nested Route
  </tabs.tab>
</PaperTabs>

{{liquid-outlet class="md-padding"}}
Index
Nested Route

Nested Route

This content lives in a nested "nested-route" route.

Note: transitions were implemented using liquid-fire.

Sometimes we need to use tabs with routes. If you pass an href property to a tab, it will render itself as an <a> tag.

Hint: use ember-href-to addon to easily generate urls for your routes. It plays really well with paper-tabs, paper-buttons and even paper-items.

Hint: for Ember versions less than 2.15, use the ember-router-service-polyfill addon to easily retrieve the current route name and use it as the selected value to paper-tabs.

API Usage

Option Type Description
accent boolean Pass true to enable accent color scheme.
borderBottom boolean Use true to enable border beneath tabs. Default is false.
onChange action An action triggered when the active tab changes.
primary boolean Pass true to enable primary color scheme.
selected string or number Value of the active tab. Each tab automatically gets an index as its value. Default is 0 (the first tab active).
stretch boolean or matchMedia query Use true/false to permanently enable/disable tab stretching. You can also use a matchMedia query to enable tab stretching only at certain viewport sizes. Default value is sm ((min-width: 600px) and (max-width: 959px)).
tabs.tab API
disabled boolean Pass true to disable the tab button.
href string You can pass an href to the tab button to render a link. Hint: use ember-href-to to generate route urls.
isSelected boolean Optionally you can set a specific tab as selected directly without relying on the global tabs value.
onClick action An action triggered when the tab button is clicked.
value string Value associated with the tab. To activate the tab, selected needs to have this value. Each tab gets a value automatically set to its index, so you don't need to use this property unless you need specific values for some special case.