Using Typescript and Tailwind CSS in a Shopify theme

Using Typescript and Tailwind CSS in a Shopify theme

Shopify themes with Tailwind CSS and Typescript

As developers we want to use tools that help make our code better and more maintainable and allow us to be our most productive. For me those tools include Tailwind CSS and Typescript. I’ve grown fond of using these tool in projects I build with Nextjs and find myself reaching for them when I develop Shopify themes. This post is a guide to using Typescript and Tailwind in Shopify themes.

If you want to skip the explanation and view the code check out the Tradewind starter theme on Github.

Dev Dependencies

To get started we’ll need to install some dev dependencies in our project. We’ll use yarn for this tutorial but npm or pnpm would work as well.

Create your package.json in the theme’s root directory.

yarn init

Create or update package.json file in root directory. Init and follow the steps in the terminal.

Vite

Our dev environment will be powered by Vite. Vite will transpile our Typescript to Javascript. It will also build Tailwind with JIT, which builds a stylesheet with only the classes used in your project. We’ll also use Postcss to add vendor specific prefixes for cross browser support.

yarn add vite fast-glob -D

Install Vite and fast-glob. fast-glob is a plugin to traverse our directory and find files that match patterns we provide it.

Typescript

TypeScript has helped me catch small bugs early in development. It also integrates with editors like VS Code to provide helpful autocompletions.

yarn add typescript ts-node -D

Tailwind CSS

Tailwind is all the rage these days, and for good reason. I am able to iterate much faster without having to think about creating class names and worrying about inheritance.

yarn add tailwind postcss autoprefixer -D

.shopifyignore

If you’re using the Shopify CLI for themes you can add a .shopifyignore file to the root of your theme directory to tell the CLI not to push certain files to Shopify’s servers.

*.cjs
src
vite.config.ts
tsconfig.json
package.json
yarn.lock

Our .shopifyignore file ignores our src directory and other config files.

Vite configuration

In our config file we will set build options that tell Vite what to do.

import fg from 'fast-glob'
import { defineConfig } from 'vite'
 
export default defineConfig({
  build: {
    outDir: 'assets',
    emptyOutDir: false,
    rollupOptions: {
      input: 'src/**/*.{ts,js,css}',
      output: {
        dir: 'assets',
        entryFileNames: '[name].js',
        assetFileNames: '[name].[ext]',
      },
      plugins: [
        {
          name: 'glob-input',
          options(options) {
            const inputs = typeof options.input === 'string' ? [options.input] : options.input
 
            return Array.isArray(inputs)
              ? { ...options, input: inputs.flatMap((input) => fg.sync(input)) }
              : null
          },
        },
      ],
    },
  },
  plugins: [],
})

vite.config.cjs

What’s happening?

  • outDir : Directory relative from root where build output will be placed.
  • emptyOutDir: We set this to false so our outDir is not emptied and replaced each time Vite builds. This is a nice feature but our outDir is the assets folder where you’ll probably have other files than what is built from Vite.
  • rollupOptions: Directly customize the underlying Rollup bundle (see docs).
  • rollupOptions.input: Files that match this pattern will be built with Vite.
  • glob-input: We’re adding a plugin to pass our input to fast-glob for faster file traversing.

Tailwind configuration

Let’s add a Tailwind config file with some options.

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ['./**/*.liquid', './src/**/*.{ts,js}'],
  theme: {
    extend: {
      fontFamily: {
        body: 'var(--font-body-family)',
        heading: 'var(--font-heading-family)',
      },
      colors: {
        text: 'rgba(var(--color-base-text), <alpha-value>)',
        accent1: 'rgba(var(--color-base-accent-1), <alpha-value>)',
        accent2: 'rgba(var(--color-base-accent-2), <alpha-value>)',
        background1: 'rgba(var(--color-base-background-1), <alpha-value>)',
        background2: 'rgba(var(--color-base-background-2), <alpha-value>)',
      },
    },
  },
  plugins: [],
}

tailwind.config.cjs

What’s happening?

  • /** @type {import('tailwindcss').Config} */: Add Typescript types for better intellisense.
  • content: Tell Tailwind where to look for class names. This powers the Just In Time Engine that builds your stylesheet with the bare minimum CSS you need.
  • theme.extend: We can extend the default Tailwind theme to use CSS variables you add in theme.liquid or somewhere else in your theme. This is useful to allow the Tailwind theme to be controlled from theme settings in the Shopify admin.

Base styles

With Tailwind you don’t have to write stylesheets you just use the class names in your markup. You will create one global stylesheet that imports a reset and some base styles. This file will be in your src folder so it gets built with Vite.

@tailwind base;
@tailwind components;
@tailwind utilities;

src/base.css

Postcss Configuration

Be sure to add the Postcss config for Tailwind.

module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}

postcss.config.cjs

Development workflow

Now that we have everything installed and configured we’re ready to start building our theme. I use 2 terminal windows to run yarn scripts I’ve added to package.json.

{
  "name": "tailwind-typescript-theme",
  "version": "0.0.1",
  "scripts": {
    "dev": "vite build --watch",
    "shopify": "shopify theme dev --store=REPLACE_WITH_YOUR_STORE",
    "build": "tsc && vite build"
  },
  "devDependencies": {
    "autoprefixer": "^10.4.13",
    "fast-glob": "^3.2.12",
    "postcss": "^8.4.21",
    "tailwindcss": "^3.2.4",
    "ts-node": "^10.9.1",
    "typescript": "^4.9.5",
    "vite": "^4.1.1"
  }
}

package.json

Yarn scripts

  1. yarn dev: This runs our Vite configuration and watches for changes.
  2. yarn shopify: This spins up your dev server for your Shopify theme. Be sure to replace the —store flag with your Shopify store.

Once you’re up and running you can edit your theme files and use Tailwind classes and Vite will build the necessary stylesheet. The Shopify CLI will see Vite changed a file and hot reload your theme and keep everything in sync. You can add Typescript files in you src folder for any functionality or user interaction you need on your theme.

I’ve found this set up to be simple to set up, yet really powerful. I hope this guide helps you start writing Shopify themes with Tailwind CSS and Typescript.

If you want to see an example of this in practice check out the Tradewind starter theme on Github.

If you have questions or feedback you can reach me on twitter. Follow me there for more guides and updates like this.