I have been working with Chakra UI Vue for several months. I am using Chakra in a side project to learn more about JAMStack and Vue/Nuxt. I am drawn to Chakra UI because of its practical set of components, and its focus on accessibility. This is the first article in a series I will be publishing about Vue and Chakra. I hope you enjoy!
One of the components I have been working with a lot is the tabs component. Tabs works well when presenting content. I have also been using it to driver high-level option selection for specific processes and user flows. Let's jump right in...
This post assumes you already have a Nuxt project setup with Chakra installed, as well as auto-imports enabled.
The standard way of setting up tabs using Chakra is using a parent c-tabs
element, containing a single c-tab-list
and single c-tab-panels
element.
<c-box>
<c-tabs>
<c-tab-list>
<c-tab>One</c-tab>
<c-tab>Two</c-tab>
<c-tab>Three</c-tab>
</c-tab-list>
<c-tab-panels>
<c-tab-panel>
<p>one!</p>
</c-tab-panel>
<c-tab-panel>
<p>two!</p>
</c-tab-panel>
<c-tab-panel>
<p>three!</p>
</c-tab-panel>
</c-tab-panels>
</c-tabs>
</c-box>
It is important to ensure you have the same number of c-tab-panel
elements as you do c-tab
elements. Not doing so may mean your content is not accessible to the user. The order is also critical to this working, as the first c-tab
button will correspond to the first c-tab-panel
element. This is quick to get up and running. Note, each c-tab
becomes a button when it renders.
In addition to the separation of content, I also want to know which tab a user has selected. To do this I recommend moving to a different pattern. This pattern involves moving the tab options to an array and then using Vues v-for
directive look to generate the c-tab-list
elements.
<c-box>
<c-tabs>
<c-tab-list>
<c-tab v-for="tab in tabs" :key="tab">{{
tab
}}</c-tab>
</c-tab-list>
...
</c-tabs>
</c-box>
We have now introduced a new data object here.. tabs
. Lets set it up so the above code works:
data() {
return {
tabs: ['One', 'Two', 'Three'],
tabIndex: 0,
}
},
We then call a method on the @change
event, to change the tabIndex value:
<c-tabs @change="setTabIndex">
<c-tab-list>...
...
methods: {
setTabIndex(index) {
this.tabIndex = index
},
}
As things are now, tabIndex
will change as the user selects a different tab, but we don't yet know which option the user has selected, just its index value. To may the index value, back to the array, we then use a computed property to give us the selected tab text:
computed: {
selectedTab() {
return this.tabs[this.tabIndex]
},
}
We now have the selectedTab
, and tabIndex
values in the parent component, which we can used to drive other behaviour.
For one final feature, we can then drive the default index, property in the c-tabs element using the tabIndex field:
<c-tabs :default-index="tabIndex" @change="setTabIndex" >
By doing this, you can set the initial tab selection.
Limitations of this approach
Your c-tab styling needs to be simple. Adding images or icons to your tab may over-complicate things. When using library components like this, keep it simple.
Another limitation may present itself if you want to enable/disable a tab. In this case, the following pattern works better.
Alternative
To enable a single tab to be disabled, the following approach can be applied.
<c-tab-list>
<c-tab>{{ tabs[0] }}</c-tab>
<c-tab :is-disabled="tabTwoDisabled">{{ tabs[1] }}</c-tab>
<c-tab>{{ tabs[2] }}</c-tab>
</c-tab-list>
data() {
return {
tabs: ['One', 'Two', 'Three'],
tabIndex: 0,
tabTwoDisabled: false,
}
},
This maintains the array of options, but gives the programmer the ability to enable/disable a single tab.
Summary
Chakra's tabs are a joy to work with, as long as you keep it simple. If you also want to know the current active tab, then the above pattern works well.
Top comments (0)