Part 11 - User Interface 1

Let's get buildin’!

Last updated by Red Cap Tom on June 24, 2020 at 12:31 +0300

This is no longer maintained

This tutorial series was cowardly abandoned by its creator mid-way due to (exciting!) circumstances. While I can't promise I'll ever finish it, I hope you found some of it useful. If you really-really-really-really want me to finish it, nag me at hey@redcaptom.com.

The Video (Scroll down for the article)

Coming soon!

Building the User Interface

Alright, we're finally here - it's time to get building!

If you follow the official tutorials, the way Shopify teaches you how to build apps revolves around the backend first, and the frontend later. I take a different approach, mostly for the sake of speed of iteration (it's much faster to mock a backend in order to build a frontend, than it is to mock a frontend in order to build a backend IMHO). Another advantage is that you don't end up writing useless backend endpoints that never get called - once the front-facing interface is all lined up, it's clear what needs building on the backend.

Getting ready

From now on, every line of code will go into a Git repository, with every post in the series represented as a commit. This is to allow you to follow along as I do my thing, and so you can revert back (more on this later) if you get stuck somewhere along the way.

Note that the link I post here is to the tree of the relevant commit. This might sound complicated, but I'd like to assure you that it's not - it's a feature of Git exposed by Github. All that means from your perspective is that the state of the repository in that link - i.e. the files you will see - match the state of the repository when I wrote this tutorial. Here is the state of the repository for this tutorial.

If you need further explanation - please let me know!

a Note About the Terminal

It's probably obvious by now that I'm not using Windows for these tutorials. I'd really like to be able to contribute more to the Windows-folk out there (I assume you guys are the majority here), and if you recall I tried to give Windows alternatives when unix tools were unix-only (read: nvm-windows ). If at any point you're not sure which command is which in Windows, just email me at hey@redcaptom.com and I'll edit the information in.

Recall our previous mockup:

mockup

We will now attempt to recreate it in React and Shopify Polaris. Let's first get the correct node version (we'll use the LTS version which is 12.18.0 at the time of writing - this version will be supported for a long while from now). For that we'll need nvm , which you can get from here.

This makes sure we will have the correct version added to source control, allowing anyone who uses the project to use the same Node.js version that we do.

nvm install 12.18.0 && \
nvm use 12.18.0

From here on we have two options: We either roll our own project scaffolding, or we use a scaffolding tool to do the work for us. Remember - this is not the final version of our app, which will use Next.js as the main backbone. This is just an experimentation playground - one step removed from all the complexity - where we can build our React & Polaris interface in an isolated way, away from the full app.

For that purpose, then, we will use create-react-app that we've seen in the React sidestep, add Polaris to it and voila - we're good to go!

cd ~ && \
npx create-react-app countries-we-ship-to-button && \
countries-we-ship-to-button \
&& echo "12.18.0" > .nvmrc

Wait for that bad boy to finish, and you will find yourself inside the project folder. Note that last line there, that makes sure we can always do nvm use inside the folder to make sure we're using the correct version of Node.js in the project.

In order to begin work on the interface, we're going to need Shopify Polaris:

npm install @shopify/polaris

Ignore any warnings that come by - we're using a very mainstream package with great support. If something does not work out of the box in this stage - it's probably not the package's fault.

By the way - that @ there, in @shopify/polaris ? That's called a “Scoped NPM Package”, and it means that this is an official module from Shopify. Goodie! :)

Starting For Real Now

Let's dive in! The scaffolding that create-react-app does allows us to use App.js for experimentation - everything is loaded up and ready to go. Your App.js should look like this:

import React from "react";
import logo from "./logo.svg";
import "./App.css";

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

And we can get going. Let's first turn the functional component into a class component, since this component is going to be rather large, and I prefer to have my larger components as classes and my smaller ones as functional components:

import React from "react";

class App extends React.Component {
  render() {
    return (

    );
  }
}

export default App;

We can now import Polaris (note how we're importing both the library and they style files - this is just because we're playing with the interface here manually, and will be abstracted away once we move over to Next.js), and specifically the <Page> component, which will be the first Polaris component we use:

import React from "react";
import { Page } from "@shopify/polaris";
import "@shopify/polaris/styles.css";

class App extends React.Component {
  render() {
    return (
      <Polaris.Page
        title="Welcome!"
        subtitle="Please select the type of button you'd like to generate for your site:"
      ></Polaris.Page>
    );
  }
}

export default App;

Let's run our code, to see how it looks like live! Type the following into your terminal:

npm start

And you should see the following error message:

image-20200612231757480

This is perfectly fine, and has to do with how Shopify app are expected to be built. Shopify has a special component called AppProvider that wraps all Shopify apps, allowing all the components in the app to share a set of properties across the board. Don't fuss too much about it right now - we'll deal with it later. For now, just add it to your code to make sure you pass the check:

import React from "react";
import { Page, AppProvider } from "@shopify/polaris";
import "@shopify/polaris/styles.css";

class App extends React.Component {
  render() {
    return (
      <AppProvider>
        <Page
          title="Welcome!"
          subtitle="Please select the type of button you'd like to generate for your site:"
        ></Page>
      </AppProvider>
    );
  }
}

export default App;

You should now see the following:

image-20200612233909383

Which means that Polaris is properly installed, and we have created our first page!

We'd like to now create a proper layout for our page. Fortunately, Polaris provides the Layout component to let us scaffold the page properly. Let's add it now to create two half-sections for our page, just like in the schema we drew up before:

import React from "react";
import { Page, AppProvider, Layout } from "@shopify/polaris";
import "@shopify/polaris/styles.css";

class App extends React.Component {
  render() {
    return (
      <AppProvider>
        <Page
          title="Welcome!"
          subtitle="Please select the type of button you'd like to generate for your site:"
        >
          <Layout>
            <Layout.Section oneHalf>
              <h1>First Half</h1>
            </Layout.Section>
            <Layout.Section oneHalf>
              <h1>Second Half</h1>
            </Layout.Section>
          </Layout>
        </Page>
      </AppProvider>
    );
  }
}

export default App;

You should now see something like this:

image-20200612233808821

Note that the Layout component has a sub-component called Section . This is what the Layout.Section syntax means - it's a component within a component. Specifically, since a component is actually a function, Section is a property of that function, that just happens to be another function. An in React-speak, this is a component nested inside another component.

Note also the oneHalf property (i.e. ‘prop’) we gave the Layout.Section component - this is one variant out of a few (see here) that we can give the section to form a “grid” of sorts on the page. This is useful if you'd like to have columns in your page (created by multiple Section s in the same Layout , each with a oneHalf or oneThird property supplied to it).

But this is still not a great look, since the headers are kind of “floating” in the page. Let's wrap them in a Card component, shall we?

import React from "react";
import { Page, AppProvider, Layout, Card } from "@shopify/polaris";
import "@shopify/polaris/styles.css";

class App extends React.Component {
  render() {
    return (
      <AppProvider>
        <Page
          title="Welcome!"
          subtitle="Please select the type of button you'd like to generate for your site:"
        >
          <Layout>
            <Layout.Section oneHalf>
              <Card title="First Half"></Card>
            </Layout.Section>
            <Layout.Section oneHalf>
              <Card title="Second Half"></Card>
            </Layout.Section>
          </Layout>
        </Page>
      </AppProvider>
    );
  }
}

export default App;

It should now look like this:

image-20200612234413946

A careful observer might note that I omitted sectioned as a prop from Layout . This is because sectioned causes the sections to stack vertically, while I want the layout to stack horizontally. To be honest, I missed this fact on my first run on the app, and only caught it when writing this post. These types of details might slip between the cracks here and there - please let me know if I leave something out or miss a beat in the comments!

Let's add some content into our cards, by sectioning it out - this will later act as a menu from which the customer can choose which type of button they'd like to have in their website. That way, the content of each selection will be a demo of one variant of the button (we will actually implement that button later, so I'll use a dummy one for now). Note that this is similar in nature to Section ing out the Layout interface like we did before:

import React from "react";
import { Page, AppProvider, Layout, Card } from "@shopify/polaris";
import "@shopify/polaris/styles.css";

class App extends React.Component {
  render() {
    return (
      <AppProvider>
        <Page
          title="Welcome!"
          subtitle="Please select the type of button you'd like to generate for your site:"
        >
          <Layout>
            <Layout.Section oneHalf>
              <Card title="Full Button Variant">
                <Card.Section title="Demo">
                  <button>Dummy Full Button</button>
                </Card.Section>
              </Card>
            </Layout.Section>
            <Layout.Section oneHalf>
              <Card title="Empty Button Variant">
                <Card.Section title="Demo">
                  <button>Dummy Empty Button</button>
                </Card.Section>
              </Card>
            </Layout.Section>
          </Layout>
        </Page>
      </AppProvider>
    );
  }
}

export default App;

image-20200612234732727

Each Card.Section can have a title, which we use here. And… I think this is enough for this post. We now have a working playground to play with, as well as a start to our product page! Stay tuned for the rest of the interface in the upcoming tutorials.

An offer

If you're working on a Shopify app, and your app uses Polaris for the front-end, I want to hear from you. I am willing to sit down and run a debug session / add a new feature with you for your application, if you agree to stream it live with me (or record it and publish it later). It's not easy writing a full-stack JS app, doubly so when you're not from within the ecosystem. Let's do it together and help all the people! :)

E-Mail me at hey@redcaptom.com, and let's set it up.