Skip to content

fix(tabs): various fixes and improvements (Fixes: #2327, #2148. Closes: #2403, #2180) #2442

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 83 commits into from
Jan 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
cd462b2
tab: inject parent tabs reference
tmorehouse Jan 11, 2019
bfb0f39
tabs: provide reference to self to tab children
tmorehouse Jan 11, 2019
710148c
Update tab.js
tmorehouse Jan 11, 2019
d2e5433
Update tab.js
tmorehouse Jan 11, 2019
5fb3622
Update tabs.js
tmorehouse Jan 11, 2019
1fd2c27
Update tab.js
tmorehouse Jan 11, 2019
09be340
Update tab.js
tmorehouse Jan 11, 2019
18bb64c
lint
tmorehouse Jan 11, 2019
b449568
Update tab.js
tmorehouse Jan 12, 2019
d5b8140
Update tab.js
tmorehouse Jan 12, 2019
3c38694
Update tabs.js
tmorehouse Jan 12, 2019
cc7765b
lint
tmorehouse Jan 12, 2019
6741bee
Update tabs.js
tmorehouse Jan 12, 2019
2bb30a8
lint
tmorehouse Jan 12, 2019
8a4a297
Update tab.js
tmorehouse Jan 12, 2019
aec4417
debugging stuff
tmorehouse Jan 12, 2019
34dc892
Update tabs.js
tmorehouse Jan 12, 2019
f520cf2
lint
tmorehouse Jan 12, 2019
56b78d6
Update tabs.js
tmorehouse Jan 12, 2019
b4e7bce
Update tabs.js
tmorehouse Jan 12, 2019
d4a699d
Update tabs.js
tmorehouse Jan 12, 2019
bcdbc40
Update tabs.js
tmorehouse Jan 12, 2019
e1ec16e
Update tabs.js
tmorehouse Jan 12, 2019
41f47fd
lint
tmorehouse Jan 12, 2019
ac59727
Update tabs.js
tmorehouse Jan 12, 2019
ea02b02
Update tabs.js
tmorehouse Jan 12, 2019
9055b78
Update tab.js
tmorehouse Jan 12, 2019
4fe2a86
Update tab.js
tmorehouse Jan 12, 2019
7a15ec2
Update tab.js
tmorehouse Jan 12, 2019
f48deb6
Update tabs.js
tmorehouse Jan 12, 2019
b13d5f8
Update tabs.js
tmorehouse Jan 12, 2019
e6ff08b
Update src/components/tabs/tab.js
jacobmllr95 Jan 12, 2019
65409f5
Update tabs.js
tmorehouse Jan 12, 2019
87116fd
Update tabs.js
tmorehouse Jan 12, 2019
1ef91fd
debug title slot reactivity
tmorehouse Jan 12, 2019
d589a5f
Update tab.js
tmorehouse Jan 12, 2019
456d198
more debug code
tmorehouse Jan 12, 2019
158c2a4
Update tabs.js
tmorehouse Jan 12, 2019
21cb01d
Update tabs.js
tmorehouse Jan 12, 2019
f6269a2
Update tab.js
tmorehouse Jan 12, 2019
e1837d9
Update tabs.js
tmorehouse Jan 12, 2019
52a0fa0
lint
tmorehouse Jan 12, 2019
00502b0
b-tab: make active prop syncable
tmorehouse Jan 12, 2019
b7781e3
Update tabs.js
tmorehouse Jan 13, 2019
7669b5f
Update tab.js
tmorehouse Jan 13, 2019
86b1c28
Update tabs.js
tmorehouse Jan 13, 2019
e8e10fb
Update tab.js
tmorehouse Jan 13, 2019
8dc7ed2
Update tab.js
tmorehouse Jan 13, 2019
035bae9
Update tabs.js
tmorehouse Jan 13, 2019
62756f3
Update tab.js
tmorehouse Jan 13, 2019
0650d53
Update tab.js
tmorehouse Jan 13, 2019
2cc62b8
Update tabs.js
tmorehouse Jan 13, 2019
180acc0
lint
tmorehouse Jan 13, 2019
367dde3
lint
tmorehouse Jan 13, 2019
895925f
debugging
tmorehouse Jan 13, 2019
6befabd
Update tabs.js
tmorehouse Jan 13, 2019
e430926
Create tab.spec.js
tmorehouse Jan 13, 2019
4fd3999
lint
tmorehouse Jan 13, 2019
92102b8
lint tests
tmorehouse Jan 13, 2019
bc991f7
Update tab.spec.js
tmorehouse Jan 13, 2019
c0a8531
Update tab.spec.js
tmorehouse Jan 13, 2019
bcaa2e0
Update tab.spec.js
tmorehouse Jan 13, 2019
54a32b0
Update tab.spec.js
tmorehouse Jan 13, 2019
5232e54
Update tab.spec.js
tmorehouse Jan 13, 2019
9698e6c
Update tab.spec.js
tmorehouse Jan 13, 2019
e84a9c8
Update tab.spec.js
tmorehouse Jan 13, 2019
4420bfa
Update tab.spec.js
tmorehouse Jan 13, 2019
58a9c26
Update tab.spec.js
tmorehouse Jan 13, 2019
d364914
Update tab.spec.js
tmorehouse Jan 13, 2019
ddf4b93
Update tab.spec.js
tmorehouse Jan 13, 2019
bb4d7cb
Update tab.spec.js
tmorehouse Jan 13, 2019
93a4473
Update tab.spec.js
tmorehouse Jan 13, 2019
f56f6a6
Update tab.spec.js
tmorehouse Jan 13, 2019
c76125f
Update tab.spec.js
tmorehouse Jan 13, 2019
95d70d2
Update tab.spec.js
tmorehouse Jan 13, 2019
ba297a7
Update tab.spec.js
tmorehouse Jan 13, 2019
95653b9
Update tab.spec.js
tmorehouse Jan 13, 2019
2064ade
Update tab.js
tmorehouse Jan 13, 2019
173603f
Update tab.js
tmorehouse Jan 13, 2019
c207088
Update tab.js
tmorehouse Jan 13, 2019
4bdca69
Update README.md
tmorehouse Jan 13, 2019
2feb50a
Update README.md
tmorehouse Jan 13, 2019
1cd3f69
Update README.md
tmorehouse Jan 13, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 104 additions & 72 deletions src/components/tabs/README.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,40 @@
# Tabs

> Create tabbable panes of _local content_. The tabs component is built upon navs and cards
> internally.
> Create a widget of tabbable panes of _local content_. The tabs component is built upon navs and cards
> internally, and provides full keyboard navigation control of the tabs.

For navigation based tabs, use the [`<b-nav>`](/docs/components/nav) component and
[`<b-card>`](/docs/components/card) component instead.
For navigation based tabs (i.e. tabs that would change the URL), use the
[`<b-nav>`](/docs/components/nav) component instead.


## Basic usage

```html
<b-tabs>
<b-tab title="first" active> <br />I'm the first fading tab </b-tab>
<b-tab title="second"> <br />I'm the second tab content </b-tab>
<b-tab title="disabled" disabled> <br />Disabled tab! </b-tab>
<b-tab title="first" active><p class="m-3">I'm the first fading tab</p></b-tab>
<b-tab title="second"><p class="m-3">I'm the second tab content</p></b-tab>
<b-tab title="disabled" disabled><p class="m-3">Disabled tab!</p></b-tab>
</b-tabs>

<!-- basic.vue -->
```

**Tip:** You should supply each child `<b-tab>` component a unique `key` value if dynamically
adding, removing, showing, or hiding `<b-tab>` components. The `key` attribute is a special Vue
attribute, see https://vuejs.org/v2/api/#key).
adding or removing `<b-tab>` components (i.e. `v-if` or for loops). The `key` attribute is a
special Vue attribute, see https://vuejs.org/v2/api/#key).


## Cards Integration

Tabs support integrating with bootstrap cards. Just add the `card` property to `<b-tabs>`. and place
it inside a `<b-card>` component. Note that you should add `no-body` prop on `<b-card>` component in
order to propertly decorate the card header and remove the extra padding introduced by `card-body`.
it inside a `<b-card>` component. Note that you should add `no-body` prop on the `<b-card>` component
in order to propertly decorate the card header and remove the extra padding introduced by `card-body`.

```html
<b-card no-body>
<b-tabs card>
<b-tab title="Tab 1" active key="tab-1"> Tab Contents 1 </b-tab>
<b-tab title="Tab 2" key="tab-2"> Tab Contents 2 </b-tab>
<b-tab title="Tab 1" active> Tab Contents 1 </b-tab>
<b-tab title="Tab 2"> Tab Contents 2 </b-tab>
</b-tabs>
</b-card>

Expand All @@ -47,19 +48,19 @@ When `<b-tabs>` is in `card` mode, each `<b-tab>` sub-component will automatical
```html
<b-card no-body>
<b-tabs card>
<b-tab no-body title="Picture 1" active key="tab-1">
<b-tab no-body title="Picture 1">
<b-card-img bottom src="https://picsum.photos/600/200/?image=21" />
<b-card-footer>Picture 1 footer</b-card-footer>
</b-tab>
<b-tab no-body title="Picture 2" key="tab-2">
<b-tab no-body title="Picture 2">
<b-card-img bottom src="https://picsum.photos/600/200/?image=25" />
<b-card-footer>Picture 2 footer</b-card-footer>
</b-tab>
<b-tab no-body title="Picture 3" key="tab-3">
<b-tab no-body title="Picture 3">
<b-card-img bottom src="https://picsum.photos/600/200/?image=26" />
<b-card-footer>Picture 3 footer</b-card-footer>
</b-tab>
<b-tab title="Text" key="tab-4">
<b-tab title="Text">
<h5>This tab does not have the <code>no-body</code> prop set</h5>
Quis magna Lorem anim amet ipsum do mollit sit cillum voluptate ex nulla tempor. Laborum
consequat non elit enim exercitation cillum aliqua consequat id aliqua. Esse ex consectetur
Expand All @@ -72,9 +73,10 @@ When `<b-tabs>` is in `card` mode, each `<b-tab>` sub-component will automatical
<!-- with-card-nobody.vue -->
```

Setting the `no-body` prop on `<b-tab>` will have no affect when `<b-tabs>` is not in `card` mode
**Note:** Setting the `no-body` prop on `<b-tab>` will have no affect when `<b-tabs>` is not in `card` mode
(as the `card-body` class is only set when in `card` mode).


## Pills variant

Tabs use the `tabs` styling by default. Just add `pills` property to `<b-tabs>` for the pill style
Expand All @@ -83,8 +85,8 @@ variant.
```html
<b-card no-body>
<b-tabs pills card>
<b-tab title="Tab 1" active key="tab-1"> Tab Contents 1 </b-tab>
<b-tab title="Tab 2" key="tab-2"> Tab Contents 2 </b-tab>
<b-tab title="Tab 1" active> Tab Contents 1 </b-tab>
<b-tab title="Tab 2"> Tab Contents 2 </b-tab>
</b-tabs>
</b-card>

Expand All @@ -98,8 +100,8 @@ Visually move the tab controls to the bottom by setting the prop `end`
```html
<b-card no-body>
<b-tabs pills card end>
<b-tab title="Tab 1" active key="tab-1"> Tab Contents 1 </b-tab>
<b-tab title="Tab 2" key="tab-2"> Tab Contents 2 </b-tab>
<b-tab title="Tab 1" active> Tab Contents 1 </b-tab>
<b-tab title="Tab 2"> Tab Contents 2 </b-tab>
</b-tabs>
</b-card>

Expand All @@ -125,9 +127,9 @@ tabs work with or without `card` mode enabled.
```html
<b-card no-body>
<b-tabs pills card vertical>
<b-tab title="Tab 1" active key="tab-1"> Tab Contents 1 </b-tab>
<b-tab title="Tab 2" key="tab-2"> Tab Contents 2 </b-tab>
<b-tab title="Tab 3" key="tab-3"> Tab Contents 3 </b-tab>
<b-tab title="Tab 1" active> Tab Contents 1 </b-tab>
<b-tab title="Tab 2"> Tab Contents 2 </b-tab>
<b-tab title="Tab 3"> Tab Contents 3 </b-tab>
</b-tabs>
</b-card>

Expand All @@ -139,9 +141,9 @@ Visually move the tab controls to the right hand side by setting the `end` prop:
```html
<b-card no-body>
<b-tabs pills card vertical end>
<b-tab title="Tab 1" active key="tab-1"> Tab Contents 1 </b-tab>
<b-tab title="Tab 2" key="tab-2"> Tab Contents 2 </b-tab>
<b-tab title="Tab 3" key="tab-3"> Tab Contents 3 </b-tab>
<b-tab title="Tab 1" active> Tab Contents 1 </b-tab>
<b-tab title="Tab 2"> Tab Contents 2 </b-tab>
<b-tab title="Tab 3"> Tab Contents 3 </b-tab>
</b-tabs>
</b-card>

Expand All @@ -156,9 +158,9 @@ column classes such as `col-2`, `col-3`, etc.
```html
<b-card no-body>
<b-tabs pills card vertical nav-wrapper-class="w-50">
<b-tab title="Tab 1" active key="tab-1"> Tab Contents 1 </b-tab>
<b-tab title="Tab 2" key="tab-2"> Tab Contents 2 </b-tab>
<b-tab title="Tab 3" key="tab-3"> Tab Contents 3 </b-tab>
<b-tab title="Tab 1" active> Tab Contents 1 </b-tab>
<b-tab title="Tab 2"> Tab Contents 2 </b-tab>
<b-tab title="Tab 3"> Tab Contents 3 </b-tab>
</b-tabs>
</b-card>

Expand All @@ -174,9 +176,7 @@ additional custom styling._

## Fade animation

Fade is enabled by default when changing tabs. It can disabled with `no-fade` property. Note you
should use the `<b-nav-item>` component when adding contentless-tabs to maintain correct sizing and
alignment. See the advanced usage examples below for an example.
Fade is enabled by default when changing tabs. It can disabled with `no-fade` property.

## Add Tabs without content

Expand All @@ -193,32 +193,45 @@ If you want to add extra tabs that do not have any content, you can put them in
<!-- tabs-item-slot.vue -->
```

**Note:** extra (contentless) tabs should be a `<b-nav-item>` or have the class `nav-item`
with a root element of `<li>` for proper rendering.


## Add custom content to tab title

If you want to add custom content to tab title, like HTML code, icons, or another Vue component,
this possible by using `title` slot
If you want to add custom content to tab title, like HTML code, icons, or another
non-interactive Vue component, this possible by using `title` slot

```html
<b-tabs>
<b-tab active key="tab-1">
<!-- Add your custom title here-->
<b-tab active>
<template slot="title">
<b-spinner type="grow" small /> i'm <i>Custom</i> <strong>Title</strong>
</template>
<p class="m-3">Tab Contents 1</p>
</b-tab>
<b-tab>
<template slot="title">
i'm <i>Custom</i> <strong>Title</strong>
<b-spinner type="border" small /> tab 2
</template>
Tab Contents 1
<p class="m-3">Tab Contents 2</p>
</b-tab>
</b-tabs>

<!-- tabs-title-slot.vue -->
```

**Do not** place interactive elements/components inside the title slot. The tab button is a
link which does not support child interactive elements per the HTML5 spec.


## Apply custom classes to the generated nav-tabs or pills

The tab selectors are based on Boostrap V4's `nav` markup ( i.e.
`ul.nav > li.nav-item > a.nav-link`). In some situations, you may want to add classes to the `<li>`
(nav-item) and/or the `<a>` (nav-link) on a per tab basis. To do so, simply supply the classname to
the `title-item-class` prop (for the `<li>` element) or `title-link-class` prop (for the `<a>`
element). Value's can be passed as a string or array of strings.
The tab selectors are based on Boostrap V4's `nav` markup ( i.e. `ul.nav > li.nav-item > a.nav-link`).
In some situations, you may want to add classes to the `<li>` (nav-item) and/or the `<a>` (nav-link)
on a per tab basis. To do so, simply supply the classname to the `title-item-class` prop (for the
`<li>` element) or `title-link-class` prop (for the `<a>` element). Value's can be passed as a string
or array of strings.

**Note:** _The `active` class is automatically applied to the active tabs `<a>` element. You may
need to accomodate your custom classes for this._
Expand All @@ -227,9 +240,9 @@ need to accomodate your custom classes for this._
<template>
<b-card no-body>
<b-tabs card v-model="tabIndex">
<b-tab title="Tab 1" :title-link-class="linkClass(0)" key="tab-1"> Tab Contents 1 </b-tab>
<b-tab title="Tab 2" :title-link-class="linkClass(1)" key="tab-2"> Tab Contents 2 </b-tab>
<b-tab title="Tab 3" :title-link-class="linkClass(2)" key="tab-3"> Tab Contents 3 </b-tab>
<b-tab title="Tab 1" :title-link-class="linkClass(0)"> Tab Contents 1 </b-tab>
<b-tab title="Tab 2" :title-link-class="linkClass(1)"> Tab Contents 2 </b-tab>
<b-tab title="Tab 3" :title-link-class="linkClass(2)"> Tab Contents 3 </b-tab>
</b-tabs>
</b-card>
</template>
Expand Down Expand Up @@ -258,44 +271,61 @@ need to accomodate your custom classes for this._

## Keyboard Navigation

Keyboard navigation is enabled by default.
Keyboard navigation is enabled by default for ARIA compliance with tablists when
a tab button has focus.

| Keypress | Action |
| --------------------------------------------------------------------- | ---------------------------------------------- |
| <kbd>LEFT</kbd> or <kbd>UP</kbd> | Activate the previous non-disabled tab |
| <kbd>RIGHT</kbd> or <kbd>DOWN</kbd> | Activate the next non-disabled tab |
| <kbd>SHIFT</kbd>+<kbd>LEFT</kbd> or <kbd>SHIFT</kbd>+<kbd>UP</kbd> | Activate the first non-disabled tab |
| <kbd>HOME</kbd> | Activate the first non-disabled tab |
| <kbd>SHIFT</kbd>+<kbd>RIGHT</kbd> or <kbd>SHIFT</kbd>+<kbd>DOWN</kbd> | Activate the last non-disabled tab |
| <kbd>END</kbd> | Activate the last non-disabled tab |
| <kbd>TAB</kbd> | Move focus to the active tab content |
| <kbd>SHIFT</kbd>+<kbd>TAB</kbd> | Move focus to the previous control on the page |

Disable keyboard navigation by setting the prop `no-key-nav`. Behavior will now default to
regular browser navigation with TAB key.

| Keypress | Action |
| ------------------------------- | ------------------------------------------------------ |
| <kbd>TAB</kbd> | Move to the next tab button or control on the page |
| <kbd>SHIFT</kbd>+<kbd>TAB</kbd> | Move to the previous tab button or control on the page |
| <kbd>ENTER</kbd> | Activate current focused button's tab |


## Programatically activating and deactivating tabs

| Keypress | Action |
| --------------------------------------------------------------------- | ---------------------------------------- |
| <kbd>LEFT</kbd> or <kbd>UP</kbd> | Move to the previous non-disabled tab |
| <kbd>RIGHT</kbd> or <kbd>DOWN</kbd> | Move to the next non-disabled tab |
| <kbd>SHIFT</kbd>+<kbd>LEFT</kbd> or <kbd>SHIFT</kbd>+<kbd>UP</kbd> | Move to the first non-disabled tab |
| <kbd>SHIFT</kbd>+<kbd>RIGHT</kbd> or <kbd>SHIFT</kbd>+<kbd>DOWN</kbd> | Move to the last non-disabled tab |
| <kbd>TAB</kbd> | Move to the next control on the page |
| <kbd>SHIFT</kbd>+<kbd>TAB</kbd> | Move to the previous control on the page |
Use the `<b-tabs>` v-model to control which tab is active by setting the v-model to
the index (zero-based) of the tab to be shown (see example below).

Disable it by setting the prop `no-key-nav`. Behavior will now default to standard browser
navigation with TAB key.
Alternatively, you can use the `active` prop on each `<b-tab>` with the `.sync` modifier
to activate the tab, or to detect if a particular tab is active.

| Keypress | Action |
| ------------------------------- | ----------------------------------------------- |
| <kbd>TAB</kbd> | Move to the next tab or control on the page |
| <kbd>SHIFT</kbd>+<kbd>TAB</kbd> | Move to the previous tab or control on the page |
Each `<b-tab>` instance also provides two public methods to activate or deactivate
the tab. The methods are `.activate()` and `.deactivate()`, respectively. If activation
or deactivaton fails (i.e. a tab is disabled or no tab is available to move activation
to), then the currently active tab will remain active and the method will return `false`.
You will need a reference to the `<b-tab>` in order to use these methods.

**Caution:** If you have text or text-like inputs in your tabs, leave keyboard navigation off, as it
is not possble to use key presses to jump out of a text (or test-like) inputs.

## Advanced Examples

### External controls
### External controls using v-model

```html
<template>
<div>
<!-- Tabs with card integration -->
<b-card no-body>
<b-tabs small card v-model="tabIndex">
<b-tab title="General" key="tab-1"> I'm the first fading tab </b-tab>
<b-tab title="Edit profile" key="tab-2">
<b-tab title="General"> I'm the first fading tab </b-tab>
<b-tab title="Edit profile">
I'm the second tab
<b-card>I'm the card in tab</b-card>
</b-tab>
<b-tab title="Premium Plan" disabled key="tab-3"> Sibzamini! </b-tab>
<b-tab title="Premium Plan" disabled> Sibzamini! </b-tab>
<b-tab title="Info"> I'm the last tab </b-tab>
</b-tabs>
</b-card>
Expand Down Expand Up @@ -325,7 +355,7 @@ is not possble to use key presses to jump out of a text (or test-like) inputs.
<!-- tabs-controls.vue -->
```

### Dynamic Tabs
### Dynamic Tabs + tabs slot

```html
<template>
Expand All @@ -341,12 +371,14 @@ is not possble to use key presses to jump out of a text (or test-like) inputs.
</b-tab>

<!-- New Tab Button (Using tabs slot) -->
<b-nav-item slot="tabs" @click.prevent="newTab" href="#"> + </b-nav-item>
<template slot="tabs">
<b-nav-item @click.prevent="newTab" href="#"><b>+</b></b-nav-item>
</template>

<!-- Render this if no tabs -->
<div slot="empty" class="text-center text-muted">
There are no open tabs <br />
Open a new tab using + button.
Open a new tab using the <b>+</b> button above.
</div>
</b-tabs>
</b-card>
Expand Down
Loading