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)