Tabs | Create that Component #5

This is a series where I design and code various common UI components with React and styled-components.

Teemu Taskula
TaitoUnited
5 min readNov 1, 2017

--

This time we are gonna build a Tabs component that has some sweet ripple action going on from the second edition of this series.

Design

Let’s cut to the chase and see how the end result will look like:

I wanted to create something visually simple and clear that still feels familiar to people. I really like the Android tabs style, even though I’m an iPhone user, so I decided to use a thick bottom border to indicate the active tab and use the ripple effect to enhance the user interaction and make the tabs more clickable.

I really wanted to try and animate the border line on hover/click but I quickly realized that I’ve rarely seen it used successfully in the web — it always feels a bit jumpy to me… So, let’s forget that and move on 🚶.

Implementation

Here’s how you would use Tabs component in your React apps render method:

Check out the gist

As you might have noticed, the actual tab buttons are not rendered or directly defined anywhere, but instead they are created from the labels of the Tabs’ static Panel components. The label can be any valid React component so you could for example pass an icon plus a string as the label if needed.

But why not use a buttons and a panels prop in the Tabs component?

Wouldn’t that be more explicit?

Yeah it might be, but giving complex things as props makes the code less readable and less elegant in my opinion. I usually prefer composing complex things from smaller parts than stuffing everything into one component.

I’ve recently discovered the static component pattern to enhance components with sub parts that don’t need to be exported separately, and I really like it.

Before we continue I want to acknowledge that there has been emerging trends called Function as Child and Controlled Props introduced mainly by Kent C. Dodds with these great articles:

After I was done with the Tabs component I realized that I could probably have used these patterns here… Maybe I will make another blog post where I write the same Tabs component with them 🤔

Now, let’s take a look at the barebones version of the Tabs component without any styled components, responsiveness or accessibility things.

Barebones Tabs component

We are using React’s built-in children mapper to first create the tab buttons and then to select the correct tab panel based on the selected tab index. We are picking the label from the Panel components label prop like seen earlier.

You might have noticed that there’s one quite a big downside with this approach — there’s no way to change tabs without clicking one of the tab buttons. What if we wanted to change to some tab when some event happens? For this article we gonna ignore this use case to keep things simple, but if you keep on reading till the end you can take a look at the list of the possible improvements and give them a try.

Okay, enough excuses, let’s see how the full Tabs component looks like with all the bells and whistles.

Check out the gist

Let’s break things down.

So, we added a breakpoint prop (768px by default) that makes Tabs adapt to narrow screen sizes. This is how it looks on a phone:

Responsive Tabs (tablet / phone)

We also added some accessibility attributes to tell the screen reader what Tabs and it’s sub components are semantically (tablist, tab, tabpanel), and how the focus should be handled — If you select one of the tabs you can switch between them with your tabs key.

Finally, we defined all the styled components to make our Tabs look nice and neat with proper hover/active styles. Since we are using the withRipple HOC that creates an additional wrapper div for the tab buttons we had to do some style overwriting to get the buttons play nice in smaller screens.

That’s it, we are done!

Here’s once again the end result:

Exercises for the Reader

And as promised earlier, here a list of possible improvements that you can give a try:

  • Add an optional selectedTab prop to manually change the active tab
  • Add an optional onTabChange prop that is called every time tab is changed
  • Make ripple effect optional
  • Recreate Tabs with “Function as Child” and “Controlled Props” patterns

If you want me to take a look at your version of the Tabs component with the suggested improvements hit me up here or on Twitter.

Hopefully you enjoyed reading this and maybe even learned some new tricks.

Until next time 👊

PS: If you are interested how I generated the code snippets take a look at Carbon.

PPS: If you want to get the code for the Tabs component it can be found in my gists. You should also find withRipple HOC there.

We are hiring!

Do you want to build exciting and interesting apps with modern web technologies? Check out our open positions and join us at Taito United!

Can’t find positions directly suitable for you? Feeling adventurous? Send your resume and an open application to jobs@taitounited.fi — we are more than happy to hear you out and see what you got cooking 🍳

--

--

Teemu Taskula
TaitoUnited

I’m a web developer / lead UX designer at @TaitoUnited. Currently interested in creating cool stuff with #reactjs. Addicted to coffee and Medium articles.