Enjoy 20% off all plans by following us on social media. Check out other promotions!

Tabs Solution

Ex-Meta Staff Engineer


Config / API Design

Part of the complexity of building a component is designing the API for it. The tabs function accepts a root element, $rootEl, where the tabs components will be inserted. The second parameter of the tabs function is an object used to store the configuration options. At the bare minimum, we will need the following options:

  • items: A list of item objects. Each item is an object with the fields:
    • value: A unique identifier for the tab item.
    • label: The text label to show in the tab item.
    • panel: The contents to show in the tab panel when the item is active.
  • defaultValue: The default tab item/panel to show. In case the defaultValue is not provided, we'll use the first item as the value. This is assuming that items is non-empty.

The tabs function maintains the selected tab value in the state object, and it uses the DOM object to store references to the tab bar and tab panel elements.

We only need one state value in the component, which is the currently selected tab item. The initial value of this state will either come from the defaultValue option or the value of the first item.

The tabs function calls the init, update, and attachEvents functions to set up the tabs widget, update its initial state, and attach the necessary event listeners.


This function sets up the DOM elements that remain throughout the lifecycle of the component, aka they will never be destroyed. In the Tabs component, the tabs list and the tab panel are always present. This function sets up the root element and creates the tab bar and tab panel elements.


Only a single event listener is necessary in this component, which is the click event, to be added to the tablist. We make use of Event Delegation so that only a single event listener has to be added and will work for any of its child contents. This technique is useful given that we'll repeatedly destroy and recreate the DOM nodes for the tabs. If we added separate event listeners to each tab, we'd have to keep adding the event listener each time the tabs are recreated.


This function updates the tablist and tab panel elements to reflect the current selected tab value. The tablist is always changing depending on the selected value, hence it will be easier to destroy all the tabs and render them again depending on the updated state. We will also have to update the contents of the panel with the selected tab's details.

Test Cases

  • All the provided items should be displayed.
  • The default active item should be reflected correctly.
  • Selecting the tab items updates the tabpanel's contents with the active tabs's panel details.
  • Test that you are able to initialize multiple instances of the component, each with independent states.


Accessibility is a huge factor of a good Tabs component. The ARIA Authoring Practices Guide for Tabs has a long list of guidelines for the ARIA roles, states, and properties to add to the various elements of a Tab. Tabs II and Tabs III will focus on improving the accessibility of Tabs component.