Building Stripe.com's Tabbed Preview Widget From Scratch in 30 Minutes
Read time: 26 min
In this video I try to build a fully functional tabbed preview widget in HTML and CSS from scratch in 30 minutes—without looking at the original code. After the time’s up, I peek under the hood to see the approach of the original author and compare and contrast it to my approach.
The build process
Setting up a development environment
For this short project I used a very simple setup: an index.html file served by browser-sync for automatic reloads on save. It can be run without previous download or install via npx, which is included by default in node/npm installations.
Configuring the widget’s container
Since this widget doesn’t appear to respond to the window size, I used the macOS screenshot tool (command-shift-4) to measure the dimensions and simply hard-code them into the CSS.
Managing the active tab state
Sliding the content left and right based on the active tab
I wrapped the code snippets in a container and positioned it absolutely, altering the left property based on the active tab. We discuss a better approach to this later on when we inspect Stripe’s solution.
Giving the widget a 3D appearance
To give the widget a 3D appearance, I rotated the widget around the X and Y axes, but it didn’t quite have the right effect. I should have used the rotate3d() function instead.
Adding a shine effect
For the shine effect, I added an ::after pseudo-element, positioned absolutely to stretch the width and height of the container, and added a background gradient. To keep the text beneath it selectable (and tabs clickable), pointer-events: none was required so that mouse events would fall through it.
My final code
Here is what I ended up with at the end of the session.
Inspecting the original Stripe code
Differences with my approach
Aside from the fact that the Stripe code was much more polished (with additional borders, typography, syntax highlighting, etc.), there were a number things about the original code that were much improved to my version. Here are a couple:
Rather than transitioning the left property to slide the code back and forth, the original author used translateX(), which is more performant.
The original author used the <figure> element to wrap this widget, which is much more semantically correct than the div I used.
Stripe is known for adding a level of polish and detail that most engineering teams can only dream of. Here are just a couple that I noticed:
Using ::before and ::after pseudo-elements with transparent-to-opaque background gradients, the text had an appearance of sliding “under” the edges of the widget as it moved back and forth.
A tasteful box-shadow was added to augment the 3D effect of the widget.