Create Tailwind Component Library

starrbyte
Jun 23 2024

In this post I will go over how to create a Tailwind component library. We will be using Vite, Tailwind, React and GitHub.

Configure Vite

vite.config.ts
import react from "@vitejs/plugin-react";
import path from "node:path";
import { defineConfig } from "vitest/config";
import dts from "vite-plugin-dts";
import tailwindcss from "tailwindcss";
import { UserConfigExport } from "vite";
import { name as orName, peerDependencies } from "./package.json";

import { fileURLToPath } from "url";
import { dirname } from "path";

const name = orName.split("/").pop();
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const app = async (): Promise<UserConfigExport> => {
  return defineConfig({
    plugins: [
      react(),
      dts({
        insertTypesEntry: true,
      }),
    ],
    css: {
      postcss: {
        plugins: [tailwindcss],
      },
    },
    build: {
      lib: {
        entry: path.resolve(__dirname, "src/index.ts"),
        name,
        formats: ["es", "umd"],
        fileName: (format) => `${name}.${format}.js`,
      },
      rollupOptions: {
        // make sure to externalize deps that shouldn't be bundled
        external: Object.keys(peerDependencies),
        output: {
          globals: {
            react: "React",
            "react/jsx-runtime": "react/jsx-runtime",
            "react-dom": "ReactDOM",
            tailwindcss: "tailwindcss",
          },
        },
      },
    }
  });
};
// https://vitejs.dev/config/
export default app;

Configure Tailwind

import type { Config } from "tailwindcss";

const config: Config = {
  important: true,
  content: [
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
};
export default config;

Configure package.json

package.json
{
  "name": "@your-org/component-lib",
  "private": false,
  "version": "0.0.1",
  "main": "./dist/component-lib.umd.js",
  "module": "./dist/component-lib.es.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/component-lib.es.js",
      "require": "./dist/component-lib.umd.js"
    },
    "./dist/style.css": "./dist/style.css"
  },
  "publishConfig": {
    "@your-org:registry": "https://npm.pkg.github.com"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/your-org/component-lib.git"
  },
  "files": [
    "dist"
  ]
}

Add .npmrc

The .npmrc is use to authorize you when running npm publish. You will need to create a token from your GitHub developer settings. The minimum scope needed for the token is package.

@your-org:registry="https://npm.pkg.github.com"
//npm.pkg.github.com/:_authToken=${PUBLISH_TOKEN}

Add awesome components

This is were the fun begins. Now that you have everything setup you can add your components. Make sure to export the components from src/index.ts (the entry point set in vite.config.ts).

Publish package

Now you can publish your package using npm publish from the command line. I prefer to set up a GitHub action to publish when I push a new commit to the main branch. You can set your own action by adding the necessary steps in ./github/workflows. You will also need to set up an action secret PUBLISH_TOKEN so you are authorized to publish.

.github/workflows/release-please.yml
name: Publish Package

on:
  push:
    paths: ["package.json"]
    branches: ["main"]

jobs:
  publish-gpr:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v1
        with:
          node-version: 16
          registry-url: https://npm.pkg.github.com/
          scope: "@your-org"
      - run: npm install
      - run: npm run build
      - run: npm publish
        env:
          PUBLISH_TOKEN: ${{secrets.PUBLISH_TOKEN}}

Installing the package

To install your new package, add a .npmrc file

.npmrc
@your-org:registry="https://npm.pkg.github.com"
//npm.pkg.github.com/:_authToken=${PUBLISH_TOKEN}

Then create a .env file and add your publish token to the file.

.env
PUBLISH_TOKEN=YOUR_GITHUB_PUBLISH_TOKEN

Now when you run npm install @your-org/component-lib, npm will resolve the PUBLISH_TOKEN from your .env file.

.npmrc
@your-org:registry="https://npm.pkg.github.com"
//npm.pkg.github.com/:_authToken=${PUBLISH_TOKEN}

Run the npm command to install your package npm install @your-org/component-lib. And finally, import your components and use them as needed.

App.tsx
import { Button } from '@your-org/component-lib'
import { PiHandWaving } from "react-icons/pi";

const App = ()=>{
  return (
    <Button icon={<PiHandWaving />} />
  )
}