DesignDev.io logoDesignDev.io logo

  1. Home
  2. /Building a React UI Library from Scratch
  3. /Setting Up a React Component Library with Vite, TypeScript, and Tailwind v4
← Back to home

Setting Up a React Component Library with Vite, TypeScript, and Tailwind v4

Muhammad Athar

Muhammad Athar

Cover Image for Setting Up a React Component Library with Vite, TypeScript, and Tailwind v4
Muhammad Athar

Muhammad Athar

April 1, 2026·3 min read
Updated April 29, 2026
Series:Building a React UI Library from Scratch
Level:Intermediate
Tags:reacttailwindtypescriptui libraryvite
Assumes:Familiar with npm, has used Vite before, comfortable with TypeScript basics

Before you write a single component, the project needs to be set up correctly — or you'll be fighting the build config the entire series. This article covers everything: Vite in library mode, TypeScript strict config, Tailwind v4, CVA, and a working entry point you can build and inspect.


Most tutorials skip the setup. They hand you a starter repo and jump straight to components. That works for following along — but it means you never understand why the config is the way it is, and you can't reproduce it from scratch when you need to.

We're not doing that. Every file in this setup exists for a reason, and we're going to cover each one.


Why Vite for a library

Vite has a library mode that handles exactly what we need: ESM and CJS output, TypeScript declarations, and a clean build with no unnecessary assets. You configure it once and it produces a dist folder your consumers can install and import from directly.

The alternative is rolling your own Rollup config or wrestling with a CRA setup that was never designed for library output. Vite does the job cleanly with minimal config.


Initialising the project

Once that's done, clean out the template noise — delete src/App.tsx, src/App.css, src/index.css, and public/vite.svg. We won't need any of it.


Configuring Vite for library mode

Replace the default vite.config.ts with this:

A few things worth understanding here:

formats: ['es', 'cjs'] — we output both ESM and CommonJS so the library works in modern bundlers and older Node-based toolchains alike.

external: ['react', 'react-dom'] — we don't bundle React into our library. Consumers already have it. Bundling it would cause duplicate React instances and break hooks.

vite-plugin-dts — generates TypeScript declaration files (.d.ts) from our source. Without this, consumers get no autocomplete or type safety. Install it:

Setting up TypeScript

Replace tsconfig.json with:

strict: true is non-negotiable for a library. It enables strictNullChecks, noImplicitAny, and several others. If your component API has a type gap, strict mode will catch it before your consumers do.

noUnusedLocals and noUnusedParameters keep the codebase clean as it grows. It's much easier to enforce from the start than to fix later.


Installing and configuring Tailwind CSS v4

Tailwind v4 ships as a Vite plugin — no more tailwind.config.js:

Add it to vite.config.ts:

Create src/styles.css:

That's it. No config file, no content paths to specify. Tailwind v4 scans your source files automatically via the Vite plugin.


Installing class-variance-authority

CVA is how we'll manage component variants throughout this series. Install it now:

Here's a preview of what it does — we'll use this pattern for every component:

Instead of a tangle of conditional classNames, variants are declared once and composed cleanly. We'll build on this in the next article.


Setting up the entry point

Create src/index.ts. This is what consumers import from when they install your library:

Every component we build will be exported from here. The structure matters — a poorly organised entry point causes tree-shaking to fail and balloons consumer bundle sizes.


The folder structure

Here's the structure we'll follow for the entire series:

Each component lives in its own folder. The component's index.ts re-exports everything so consumers can import from the component name directly. We'll talk through this in more detail in How to structure a UI library that scales — folders, exports, and naming conventions.


Verifying the build

Run the build:

You should see a dist/ folder with:

If you see those three outputs, the setup is correct. The ESM file is what modern bundlers will use. The CJS file covers older toolchains. The .d.ts file is what gives consumers TypeScript support.

If the build fails, the most common cause is a missing src/index.ts — Vite's library mode requires the entry point to exist even if it's empty.


Up next: How to structure a UI library that scales — folders, exports, and naming conventions — the folder pattern, barrel export strategy, and naming conventions we'll use for all 40 components in this series.

Related: Publishing your first React component to npm — the complete setup — once the build is working, this is the next milestone. Worth reading ahead so you know where we're headed.

Muhammad Athar is the founder of DesignDev.io and the engineer behind everything you read here. He writes about the decisions behind building real products — the components, the architecture, and the tradeoffs that don't make it into the tutorial.

Photo by Orlando García on Unsplash


More Stuff

Publishing Your First React Component to npm — the Complete Setup
April 1, 2026·3 min read

Publishing Your First React Component to npm — the Complete Setup

Most tutorials stop at "it works on my machine." This one doesn't. Publishing to npm is where your library becomes real — installable, versioned, and usable by anyone. Here's the complete setup, including the fields most developers get wrong in package.json and how to inspect what you're actually shipping before it goes live.

Muhammad Athar

Muhammad Athar

How to structure a UI library that scales — folders, exports, and naming conventions
April 1, 2026·3 min read

How to structure a UI library that scales — folders, exports, and naming conventions

The folder structure you pick on day one is the one you'll live with across 40 components. Get it wrong and you'll be fighting your own codebase by article 10. Get it right and adding a new component takes five minutes and follows a pattern every contributor can learn in one sitting.

Muhammad Athar

Muhammad Athar

DesignDev.io logoDesignDev.io logo

Explore

  • Home
  • Search
  • Authors
  • Series
  • About Us

Account

  • Sign in

Legal

  • Privacy Policy
  • Terms of Service

© 2026 DesignDev.io · All rights reserved

Built with Next.js · Tailwind · Sanity · Vercel