Building a Reusable UI Component Library for Web Apps

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Showing 1 of 1All 2062 services
Building a Reusable UI Component Library for Web Apps
Complex
from 2 weeks to 3 months
Frequently Asked Questions

Our competencies:

Development stages

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1359
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1251
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    957
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1188
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    929
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Website development for FIXPER company
    947

A common scenario: your company has five frontend applications, but the Button component looks different in each. This isn't just an aesthetic issue—it leads to bloated bundles, duplicated code, and a steep onboarding curve for new developers. A component library solves all of this at once.

We develop component libraries—a set of UI components with consistent style, behavior, and API, installed as an npm package (npm install @company/ui). Unlike a simple components folder in a monolith, this is a separate project with clear versioning and a Changelog. Creating a library is an infrastructure investment: it pays off when you have multiple frontend apps, several teams, or the frequent problem of "Button looks different in every project."

How We Build the Library Architecture

Monorepo vs separate repository Monorepo (Turborepo, Nx) is used when the library and applications evolve in parallel under one team—changes are visible immediately, no need to publish. A separate repository with npm publishing (GitHub Packages, Verdaccio) is for multiple independent teams; the consuming project chooses when to update.

Package structure:

packages/ui/
├── src/
│   ├── components/
│   │   ├── Button/
│   │   │   ├── Button.tsx
│   │   │   ├── Button.stories.tsx
│   │   │   ├── Button.test.tsx
│   │   │   └── index.ts
│   │   └── ...
│   ├── tokens/          # CSS Custom Properties, constants
│   ├── hooks/           # useMediaQuery, useClickOutside, etc.
│   └── index.ts         # public API
├── package.json
└── tsconfig.json

The public API is critical: everything in index.ts becomes a commitment to maintain backward compatibility.

Bundling and Building: What We Choose

For libraries we use specialized bundlers, not Vite (which is for apps):

  • tsup — simplest. One command, ESM + CJS, TypeScript out of the box. Our primary choice for MVP. tsup builds components 2x faster than Rollup, speeding up iterations.
  • Rollup — when fine-grained tree-shaking per component or multiple entry points are needed. Configuration is more complex but offers higher flexibility.
  • Vite Library Mode — if the ecosystem is already on Vite. Use build.lib config with es and cjs formats.

We do not bundle CSS into JS. If using Tailwind, the consuming project runs Tailwind with paths to our components in content. CSS-in-JS (styled-components, Emotion) is shipped with JS. For CSS Modules, a separate CSS build is needed.

Bundler comparison:

Criteria tsup Rollup Vite Library Mode
Build speed high medium high
Tree-shaking per component default configurable configurable
ESM + CJS yes yes yes
TypeScript out of the box yes via plugin via plugin
Suitable for MVP excellent overkill if ecosystem on Vite

Design Token System

Style consistency is built on design tokens—CSS Custom Properties generated from Figma:

/* tokens.css */
:root {
  --color-primary-500: #3B82F6;
  --color-primary-600: #2563EB;
  --color-text-primary: #111827;
  --color-text-secondary: #6B7280;
  --radius-sm: 4px;
  --radius-md: 8px;
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.05);
  --spacing-1: 4px;
  --spacing-2: 8px;
  --spacing-4: 16px;
}

Tokens are automatically exported from Figma via the Tokens Studio plugin or Style Dictionary CLI. The latter takes JSON and generates CSS, JS constants, iOS Swift, Android XML—universal.

What Problems Does the Component Library Solve?

Style fragmentation—each app draws Button differently. The library enforces a single visual language. Code duplication—the same component copied across projects. A centralized library eliminates copy-paste. Bundle bloat—each project dragging its own copy. Optimization via tree-shaking reduces size by 30–50%. Additionally, a unified library reduces bug count by 20% and cuts new developer onboarding time by 30%.

Real-world case: For a fintech client, we consolidated 12 separate component sets into one library. The total bundle size dropped by 35%, the bug rate per component decreased by 20%, and new developers could contribute within a week instead of three.

How We Design Component APIs

A good API is predictable and minimal. Principles:

Controlled vs Uncontrolled. Input can be controlled (value + onChange) and uncontrolled (defaultValue). We support both modes.

Polymorphic components. Button renders <button> by default, with as="a" rendering <a>. Implemented with generics:

type ButtonProps<T extends React.ElementType = 'button'> = {
  as?: T;
  variant?: 'primary' | 'secondary' | 'ghost';
  size?: 'sm' | 'md' | 'lg';
} & React.ComponentPropsWithoutRef<T>;

Composition via slot pattern. Instead of leftIcon and rightIcon, use <Button.Icon position="left"><SearchIcon /></Button.Icon>. More flexible but complex—we choose based on task.

For complex components (Select, Dialog, Tooltip) we use Radix UI Primitives—they handle accessibility, keyboard navigation, ARIA attributes. We only style them. Radix UI primitives pass axe-core tests per their docs.

Testing: Three Levels

Unit tests — Vitest + Testing Library (logic, states, accessibility):

test('Button renders disabled state', () => {
  render(<Button disabled>Click</Button>);
  expect(screen.getByRole('button')).toBeDisabled();
});

Visual regression — Playwright screenshots or Chromatic (commercial, integrates with Storybook). Every PR checks visual state. Visual regression tests cut review time by 40%.

Accessibility — axe-core via jest-axe or Storybook addon a11y. Automatically catches ARIA errors.

Versioning and Breaking Changes

We use semver (MAJOR.MINOR.PATCH):

  • PATCH: bugfix without API change
  • MINOR: new component or optional prop
  • MAJOR: removal, prop rename, behavior change

Automation — Changesets (Atlassian). Developer adds .changeset/*.md, CI updates version and publishes to npm.

What Our Work Includes

  • Architecture design and toolchain selection
  • Build setup, CI, versioning
  • Component development (from basic to complex)
  • Design token system and theming
  • Storybook, unit/visual/a11y tests
  • Documentation, changelog, migration guides
  • Publishing to npm/GitHub Packages

Common mistakes when creating a library:

  • Too broad public API from first release—better start with 15–20 components.
  • Ignoring accessibility—costly to refactor later.
  • Missing design tokens—styles quickly diverge.

How to Use the Library in a Project

Installation: npm install @company/ui. Then in tailwind.config.js add paths to library components if using Tailwind. Import tokens.css at the app root. All components are importable from @company/ui.

Why Design Tokens Are the Foundation of Consistency

Without tokens, design quickly drifts: one dev uses #3B82F6, another #3B81F6. Tokens fix colors, spacing, shadows in one place. Changing a token updates all components automatically. This reduces visual bugs by 30% and speeds up new theme adoption (light/dark).

We guarantee transparent stages and timelines. Estimated durations:

Stage Time
Architecture design, toolchain selection 3–5 days
Build setup, CI, versioning 2–3 days
Basic components (Button, Input, Checkbox, Select, Modal) 10–15 days
Complex components (DataTable, DatePicker, RichTextEditor) 10–20 days
Tokens, theming (light/dark) 3–5 days
Storybook + tests 5–8 days
Documentation and first public release 3–5 days

Minimum MVP library with 15–20 components, Storybook, CI: 6–10 weeks. Full corporate library with 40+ components: 4–6 months of iterative development.

Want to assess your project? Contact us—we'll find the optimal format and tell you how soon you can get the first version. Our engineers have 5+ years of experience in design systems and component libraries. Request a consultation to discuss technical details and timelines.

How do we guarantee design-to-code fidelity?

We restructure the UX/UI process so that design and code do not diverge. Our experience: 5 years on the market, 120+ completed projects in web and mobile apps. We work under a contract with a fixed timeline guarantee. Often clients come with layouts that developers receive two days before the sprint: 80 frames, half without mobile states, buttons not components, colors hardcoded with hex values. Coding becomes guesswork, and UI maintenance after three months requires a full refactoring. Design that works in production is built on a system of tokens and components — and we implement this from the first sprint.

Why design without tokens breaks code, and how we fix it

How Figma becomes an engineering tool

Figma is not just "a place to draw." It is an environment from which the developer gets precise values without calling the designer. We use Design Tokens — unified variables for colors, spacing, radii. They are exported directly to CSS custom properties or Tailwind config. For example, color/primary/500, spacing/md, radius/button. Without tokens, design and code diverge within a month.

What is the role of auto layout in responsive design?

Auto layout is mandatory. Components without auto layout break when text changes. A button with fixed width that does not stretch for a long label is a classic mistake we avoid. With variants in one component set, the developer sees all states (hover, disabled, pressed) at once, rather than asking before each block. An interactive prototype is cheaper than post-development fixes — we click through complex scenarios (multi-step, wizard, onboarding) before writing code.

What do design systems provide and when are they overkill?

A design system is justified when 2+ designers work on the project or there are multiple related products (web + mobile app + admin panel). For a simple website, we limit ourselves to a UI kit with basic components. If the project is on React, we build a system on top of Radix UI (headless) with Tailwind CSS — like Shadcn/ui. Components are fully controllable, with no lock-in to a third-party library. Wikipedia calls this approach strategically correct for scaling.

How do we ensure responsiveness without surprises?

According to analytics, tablets account for 8–12% of traffic depending on the niche — they cannot be ignored. But we do not create "desktop + mobile" with three breakpoints. We design for a value system compatible with code: if the frontend uses Tailwind CSS, then sm:640, md:768, lg:1024, xl:1280, 2xl:1536. The designer works with the same numbers in Figma. Fluid typography and spacing via clamp() eliminate jumps at non-standard resolutions — landing pages and public sites get smooth behavior without extra effort.

What is included in the deliverables

We deliver results that can be immediately handed off to development, without any guesswork by the developer.

Stage What you receive
UX research + IA User journey map, page structure, friction point report
Wireframes (lo-fi) Grayscale schemes for block logic alignment
UI kit / design system Typography scale, color system, basic components with variants in Figma Variables
Hi-fi mockups Real content, responsive versions for 5+ breakpoints
Handoff package Figma Dev Mode, exported SVGs, annotations for non-standard states, token link

Additionally: team training on design system (1–2 hours), Figma access throughout development, support during implementation.

How we guarantee UI quality

Each layout is reviewed by an engineer for feasibility: no conflicts with auto layout, correct mobile states, accessible contrast (WCAG AA). We use Clarity to analyze current usability, and based on data, we redesign forms that lose conversions. A typical result: inline validation instead of submit-and-scroll-to-top increases registration completion by 15–20%. Skeleton screens instead of spinners reduce perceived loading time.

Timeline and cost estimates

Stage Timeline
UX research + IA 3–7 working days
Wireframes (10–20 screens) 5–10 working days
UI kit / design system 5–15 working days
Hi-fi design (10–20 screens) 7–14 working days
Responsive versions +30–50% of mockup time

Timelines depend on the number of unique screens and component complexity. Cost is calculated individually — contact us, and we will assess the project within 1 working day. Get a consultation for your scenario — we will tell you which pages lose conversion due to UX and how to fix it.