Building Stripe.com's Tabbed Preview Widget From Scratch in 30 Minutes
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 (
4) to measure the dimensions and simply hard-code them into the CSS.
Managing the active tab state
The book I referenced in the video is called Resilient Web Design by Jeremy Keith and is freely available to read online.
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
leftproperty 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
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:
::afterpseudo-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-shadowwas added to augment the 3D effect of the widget.
Any questions or suggestions about my tooling, approach, development style? What would you have done differently? I’d love to hear from you. Find me on Twitter or leave a comment on the video.
Here are the tools I used in this video:
- Text editor: Visual Studio Code with theme Right in the Teals by themer, and Fira Code font
- Browser: Brave
- Development server: Browsersync launched under npx
- Application launcher: Alfred
- Color picker: Sip