Building Your Own UI Library Package with Vite(Library Mode), React, TS, and TailwindCSS.

Right now, there’s a multitude of blog posts tackling the creation of UI libraries. My aim here is to simply share my personal experience and outline the ongoing processes involved in constructing a UI Kit with Vite (Library mode).

⚡️ Just a heads-up, let's clarify the structure of our library. We'll be styling it with Tailwind, but we won't bundle the entire Tailwind library with it. Two reasons behind this decision: firstly, Vite doesn't support shipping styles in library mode, and secondly, by taking this route, our UI library becomes versatile, ready to roll in any environment, be it SPA or SSR.

Step 1. Let’s dive right in by installing Vite

npm create vite@latest ui-kit -- --template react-ts
cd ui-kit 
code .

👉 Just a bit of cleanup—delete the /src and /public directories and the index.html file.

Step 2. Add Storybook

npx storybook init --builder=vite

This is the new zero config setting up Storybook on Vite.

Step 3. Add TailwindCSS

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

Step 4. File structure
Create the lib folder on the root of the project , Within this folder, create a main.ts file, it will serve as the central hub for exporting your components.
Additionally, create a components folder within the lib directory; this folder will serve as the primary residence for all your components.

-lib/
---components/
---main.ts

Step 5. Update Vite config
With the fundamental file structure in place, let’s fine-tune the remaining configurations. Open up the vite.config.js file and incorporate the path to your content. This step ensures that Vite recognizes and processes the specified content, aligning with the established file structure.

content: [
    "./lib/**/*.{js,ts,jsx,tsx}",
  ],

Now, go ahead and generate a tailwind.css file within the “lib” folder.
Populate this file with the necessary directives for Tailwind’s utility classes.
This step lays the foundation for leveraging TailwindCSS’s powerful utility features in your UI library.


/*tailwind.css*/
@tailwind base;
@tailwind components;
@tailwind utilities;

Step 6. Update the Vite Config
Now, let’s dive into the critical configuration file: vite.config.js.
In this step, we’ll make substantial updates. Primarily, we’re focusing on the library-related aspects. Essentially, we’re instructing Vite not to duplicate the content of the public folder, as it is unnecessary for our purposes.
Additionally, we’re providing Vite with pointers on locating the main file from which we export the components. Furthermore, we’re specifying a name and format for the generated file, ensuring compatibility with various environments such as ES Modules and UMD. We also assign a name for the exported file.
Vite works with Rollup as its bundler. Because our library will be used in an environment that already has some of these required libraries, we’re basically telling Rollup to go ahead and use what’s already there!

build: {
    copyPublicDir: false,
    lib: {
      entry: path.resolve(__dirname, "lib/main.ts"),
      name: "UI KIT",
      formats: ["es", "umd"],
      fileName: "ui-kit",
    },
    rollupOptions: {
      external: ["react", "react-dom", "react/jsx-runtime", "tailwindcss"],
    },
  },

Also, let’s add type support on the exported library, the dts plugins handle that for us.

npm install -D vite-plugin-dts
...
//vite.config.js

plugins: [react(), dts({ include: ["lib"], insertTypesEntry: true })],

The place we will update is tsconfig.js let’s include the lib path and exclude the stories folder from ts check.

Step 7. Storybook
Now let’s update the storybook with our lib address and for the preview, we need to add the tailwind.css address.

//.storybook/main.ts
stories: ["../lib/**/*.stories.@(js|jsx|mjs|ts|tsx)"],

//.storybook/preview.ts
import "../lib/tailwind.css";

Step 8. package.json
The last step, package.json, let’s update it as below:

//package.json
...
"name": "@ali-nuri/vite-tailwind-library",
...
 "private": false,
  "version": "0.0.1",
  "main": "dist/ui-kit.umd.js",
  "module": "dist/ui-kit.mjs",
  "types": "dist/main.d.ts",
  "exports": {
    ".": {
      "types": "./dist/main.d.ts",
      "import": "./dist/ui-kit.mjs",
      "require": "./dist/ui-kit.umd.js"
    },
    "./dist/style.css": "./dist/style.css"
  },
  "files": [
    "dist"
  ],
...
"scripts": {
    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
    "storybook": "storybook dev -p 6006",
    "build": "tsc && vite build",
    "build:storybook": "storybook build"
  },
...
"peerDependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },

🥳 Done! Now you can build and publish your package on GitHub, and GitLab.

Check the complete project from my GitHub.

For publishing a private packages I recommend checking GitHub npm registry and Gitlab npm registry docs.

Thanks for reading ⚡️.

Leave a Reply

Your email address will not be published. Required fields are marked *