DEV Community

Cover image for Shopify App From Scratch #10 - Shopify Polaris
Red Cap Tom
Red Cap Tom

Posted on • Edited on • Originally published at redcaptom.com

Shopify App From Scratch #10 - Shopify Polaris

Deprecation Notice

Yeah, yeah, I know. I hate it too when people abandon tutorial series mid-way. But, due to (exciting!) circumstances, I'm calling it quits for now.

I'm thinking of just dropping a link to the full repo here - it's a mess, but it's something you guys can chew on instead of my empty promises.

If you'd like me to drop it here - let me know at hey@redcaptom.com.

And, just sayin', I had a BLAST doing this. If you know something - anything - about technology, take the time to write it down as a tutorial series. You will get SO, SO much value out of it, you can't even believe it.

Until we meet again - RCT :)

The Video (Scroll down for the article)

Coming soon!

Introduction

When you're building a large collection of independent components across a large enough team, people are going to have opinions about how to design each part of the system. This, in and of itself, is not a bad thing - product managers, engineers and designers should all pitch in on the look and feel of the system to provide a holistic perspective of what's desired, what's possible and what's most awesome-looking. But there are some thing that should remain consistent across the entire stack - the colors of buttons, the fonts, the look and feel of tables, the general padding and margin and borders of elements, etc.

A while back, there was no proper name for this desired "universalism" across the front-end part of software projects. At some point, most likely around the arrival of component-based frameworks (read: React), it became apparent to some of the largest software players in the world that having a universal design language for their products is probably a good idea. Some examples include Google's Material Design, GitHub's Primer and MailChimp's Patterns.

What's in a design system?

Most modern design system consist of multiple components, which can be divided roughly into two parts:

  • Visual Guidelines - Instructions on what colors, typography, language, spacing etc. to use in the software.
  • Components - A set of often-used components that embody those visual guidelines, written in a widely used framework (React is a often a prime candidate, but you might see Vue.js or plain HTML components as well).

In the video I focus a bit more on the visual guidelines, but in this post I'll deal mostly with the components.

Why should you care?

Generally speaking, if you're building a software product as part of another software company's ecosystem, and your product is intended to complement said company's product - you'll do well to comply with their design system. It will cause your product to integrate into the platform better, will save you the trouble of making a lot of design decisions and will often also save you quite a bit of time.

This goes double for products that are directly embedded into another piece of software - like Shopify apps. There are a lot of apps out there that use their own styles (usually Bootstrap) which just looks.... bad.

If you're building something to delight your users, and you're part of a larger ecosystem - you should either conform (if the outer styles are good) or differentiate (if the outer styles are the worst). In this case, Shopify really made a good design move, and I'd offer you to conform to their standards (and, to be honest, it does not hurt your chances of getting your app approved).

Shopify Polaris - Shopify's Own Design System

Polaris is Shopify's own foray into the design system game, and I will focus specifically on polaris-react - the React-based, Polaris-compliant component set.

First and foremost, it's important to note that the components we're going to see here look a little differently than the ones we've seen before. This is because they are not written in simple JavaScript, but in a superset of JavaScript called Typescript. What is a superset, you may ask? It's a set, that contains another set, and then some. What, you may rightfully ask, are you talking about? Doesn't matter. For the sake of this discussion, TypeScript is Javascript - with types. Fun to be had by all!

Seriously though, the only reason I'm even mentioning this is because I want you to understand that Polaris is not really anything new - it's just a bunch of components neatly wrapped up in a package. You should be able to re-create them yourself if you so please, not to mention be able to understand them. However, like in the case with React, I think it serves us to observe what they look like in the wild. To that end, I will take a look at two different components, one simple and one a bit more complicated and got a bit into depth on how they're built and how to use them.

Example Component - Button

The "Hello World" of Polaris is, in my opinion, the button:

Consider the directory structure of that button (located at https://github.com/Shopify/polaris-react/tree/master/src/components/Button ):

# Button

* [tests/](./Button/tests)
  + [Button.test.tsx](./Button/tests/Button.test.tsx)
* [Button.scss](./Button/Button.scss)
* [Button.tsx](./Button/Button.tsx)
* [README.md](./Button/README.md)
* [index.ts](./Button/index.ts)
* [utils.tsx](./Button/utils.tsx)

Enter fullscreen mode Exit fullscreen mode

This feels like a lot of stuff for a button, right? Let's break it down:

  • tests - React components are, by definition, individual units of code that structure an application's UI. They are the atomic bits of your user interface, and by popular opinion should be tested individually before being combined together. It's therefore common to create tests for each component separately, and then bundle those tests in proximity to the component. This allows users to pick-and-choose the components they like, and still have unit tests available for the taking immediately. These tests are written (in Polaris's case) using a testing framework for JavaScript called Mocha, originally written by the ever-awesome TJ Holowaychuk. If you're reading this, dear TJ - we love you here in JS land. You the bomb.
  • Button.scss - There a few different ways of styling React components, and in this specific case the Shopify staff chose to use a preprocessor (Sass). Sass is similar to CSS in some ways, and is looked at as a CSS "extension language" - you have a bit more flexibility in defining your styles, and they take care of translating the Sass syntax into proper CSS. Since we will not be using Sass, I will not say anything further about it (I will mention, however, that it is one of those things I have very little knowledge about but always wanted to dive into deeper).
  • Button.tsx - The TypeScript-React file is actually a combination of two types of files - .tsx stands for TypeScript ( ts ) - with the possibility to embed JSX - ( x ). Recall that JSX is what I referred to as "HTML On Steroids" - it's what your functional components return, that end up constructing the virtual DOM. If you take a deep dive inside, you'll see that it's quite a long file (350+ lines at the time of writing), which sounds a little bit surprising given that it's just a button. But, if you look closely at the Polaris docs, you'll see that this innocent button actually has 17 different possible configurations - all accessible by adding various in-tag attributes (i.e. React props) to the button:

pic1

That's where Button.tsx comes in - it's all about the props that you pass into the button, whose mixture configures how the button will look like.

  • README.md - Just a README file.
  • index.tx - This is just an export file - it ensures everything inside this folder is accessible to files from the outside. Unless you're super into the way JS projects need to be structured due to.... reasons, then this is just a detail and nothing else.
  • utils.tsx - This file contains functions that help use the Button component from elsewhere. You will see this in action in the next section.

All of those files eventually make, for example, this:

<Button primary>Save theme</Button>

Into this:

pic2

Which is not that much, right? Well, that's until you see that very same component as part of another component, and then everything starts to make a little more sense.

Example Component - Callout Card

The beauty of Polaris, and actually React in general, is the fact that most things are re-used in some form or another in other things. In a more formal manner, a hybrid component is a component that's composed of other components - exposing only the top-most component for you to interact with.

It makes little sense for you to re-implement a button each time you need one, and doubly so if you'd like for the buttons to remain consistent across all your components. The Callout Card is component that combines a button inside of it, but you don't actually need to write <Button> anywhere yourself - the component takes care of this for you.

This is how it looks like:

pic3

See the button there? It's actually created in the CalloutCard.tsx file:

  const primaryActionMarkup = buttonFrom(primaryAction);
Enter fullscreen mode Exit fullscreen mode

And remember the utils.tsx file from the Button component? It actually contains this buttonFrom(action) funtion:

export function buttonFrom(
  {content, onAction, ...action}: ComplexAction,
  overrides?: Partial<ButtonProps>,
  key?: any,
) {
  return (
    <Button key={key} onClick={onAction} {...action} {...overrides}>
      {content}
    </Button>
  );
}
Enter fullscreen mode Exit fullscreen mode

That, unsurprisingly, creates a button out of some action , which is an abstraction of whatever it is you'd like the button to do - throw up a pop-up, call some long-running task, delete something, refresh the page etc.

Let's look at the code for the CalloutCard this time, and actually observe how we can customize it. This is how the default CalloutCard looks like when you want to use it on your front-end:

<CalloutCard
  title="An Awesome TItle"
  illustration="Some_Illustation_From_Undraw.svg"
  primaryAction={{
    content: 'Button Text',
    url: 'http://SomeLink.com',
  }}
>
  <p>Your Awesome Callout Card Text</p>
</CalloutCard>
Enter fullscreen mode Exit fullscreen mode

So you are able to customize the following options of the card:

  • title - The main piece of text the card promotes.
  • illustration - Some illustration to be placed in a strategice location in the button (see how that strategic placement is abstracted away from you? This is not a mistakle, but good design by the Shopify people). BTW, unDraw is this awesome project by the very talented Katerina Limpitsouni, that aims to provide programmers with great, royalty-free and actually-free illustrations. You will see that I try to use it whenever I can in my projects, since her illustrations resemble Shopify ones visually, and have the same color scheme.
  • primaryAction - An object to define what the button is there to "Call Out" for you to do:
    • content - The call to action, i.e. the text of the button.
    • url - The URL to access when the button is pressed. This doesn't actually have to be a URL, and can be swapped for action to perform some in-app operation (like calling a function).

I think that's enough for Polaris - there's so much to go into, and I hope in the future to do a "Quick Hits" type series, talking and giving actual working examples of every Polaris component in production. For now, though, that should be enough to give you a feel for Polaris. Moving on!

Top comments (0)