WellAlly Logo
WellAlly康心伴
Development

Building a Component Library for Health Dashboards with Storybook and Tailwind CSS

A practical, step-by-step tutorial on building a reusable and themeable React component library for health dashboards using Storybook for documentation and Tailwind CSS for styling.

W
2025-12-18
10 min read

In the fast-paced world of health tech, building intuitive and consistent user interfaces is crucial. Whether you're displaying patient vitals, tracking fitness goals, or managing appointments, a clear and reliable UI can make all the difference. However, building these interfaces from scratch for every new project is inefficient and prone to inconsistencies.

This is where a dedicated component library shines. By creating a set of reusable, well-documented, and easily themeable components, you can dramatically speed up development, improve collaboration between designers and developers, and ensure a consistent user experience across your entire product ecosystem.

In this tutorial, we'll walk you through building a component library for a health dashboard using a powerful trio of modern frontend tools: React, Storybook, and Tailwind CSS. We'll build a few core components, like a MetricCard to display vital signs and a Pill for status indicators, and get them ready to be shared and reused.

Prerequisites:

  • Solid understanding of React and JavaScript.
  • Node.js and npm/yarn installed on your machine.
  • Basic familiarity with the command line.

Understanding the Problem

Developing UIs for health dashboards presents unique challenges:

  • Data Density: Dashboards often need to display a large amount of information clearly and concisely.
  • Consistency: Vital metrics must be presented in a uniform way to avoid confusion.
  • Scalability: As the application grows, the UI needs to scale without becoming a tangled mess of styles and components.

A component library solves these problems by providing a single source of truth for your UI. It establishes a shared language for your team and makes it easy to build complex interfaces from simple, tested building blocks.

Prerequisites & Project Setup

Let's get our hands dirty and set up the development environment. We'll use Vite for a fast and modern React setup.

First, create a new React project using Vite:

code
npm create vite@latest health-dashboard-library --template react-ts
cd health-dashboard-library
npm install
Code collapsed

Next, we'll install Storybook. Navigate into your new project directory and run the Storybook init command:

code
npx storybook@latest init
Code collapsed

This command will detect that you're using React and set up all the necessary dependencies and configuration files for Storybook.

Finally, let's add Tailwind CSS to the mix for our styling needs.

code
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Code collapsed

This creates tailwind.config.js and postcss.config.js files. Now, configure your tailwind.config.js to tell it which files will contain Tailwind class names:

code
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
Code collapsed

Lastly, create a ./src/index.css file and add the Tailwind directives. This is the entry point for all of Tailwind's styles.

code
/* src/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
Code collapsed

To make sure Storybook picks up these styles, import this CSS file into .storybook/preview.ts:

code
// .storybook/preview.ts
import type { Preview } from "@storybook/react";
import '../src/index.css'; // Add this line

const preview: Preview = {
  parameters: {
    // ... existing parameters
  },
};

export default preview;
Code collapsed

Now, you can start both your Storybook and Vite dev servers:

code
# To run Storybook
npm run storybook

# To run the Vite app (optional)
npm run dev
Code collapsed

Step 1: Building a "MetricCard" Component

A health dashboard isn't complete without a way to display key metrics like heart rate, blood pressure, or steps taken. Let's create a MetricCard component.

What we're doing

We'll build a simple, reusable card that takes a label, a value, and a unit as props. It will have a clean, modern look styled with Tailwind CSS.

Implementation

First, create a new file for our component at src/components/MetricCard.tsx:

code
// src/components/MetricCard.tsx
import React from 'react';

export interface MetricCardProps {
  label: string;
  value: string | number;
  unit: string;
}

export const MetricCard: React.FC<MetricCardProps> = ({ label, value, unit }) => {
  return (
    <div className="bg-white rounded-lg shadow-md p-6 w-full max-w-xs text-center transform hover:scale-105 transition-transform duration-300">
      <div className="text-gray-500 text-sm font-medium uppercase tracking-wider">{label}</div>
      <div className="text-4xl font-bold text-gray-800 my-2">
        {value}
        <span className="text-2xl text-gray-600 ml-1">{unit}</span>
      </div>
    </div>
  );
};
Code collapsed

How it works

This is a straightforward functional React component that accepts MetricCardProps. We use Tailwind's utility classes directly in the JSX for styling. This approach keeps our styles co-located with our component logic, making it easy to see what's happening.

Creating the Story

Now, let's create a Storybook story to visualize and document this component. Create src/components/MetricCard.stories.tsx:

code
// src/components/MetricCard.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { MetricCard } from './MetricCard';

const meta: Meta<typeof MetricCard> = {
  title: 'Dashboard/MetricCard',
  component: MetricCard,
  tags: ['autodocs'],
  argTypes: {
    label: { control: 'text', description: 'The label for the metric' },
    value: { control: 'text', description: 'The value of the metric' },
    unit: { control: 'text', description: 'The unit for the metric value' },
  },
};

export default meta;
type Story = StoryObj<typeof MetricCard>;

export const HeartRate: Story = {
  args: {
    label: 'Heart Rate',
    value: '72',
    unit: 'bpm',
  },
};

export const StepsTaken: Story = {
  args: {
    label: 'Steps Taken',
    value: '8,452',
    unit: 'steps',
  },
};
Code collapsed

If you run npm run storybook, you'll now see your MetricCard component in the Storybook UI, with interactive controls to change its props!

Step 2: Creating a "Pill" Component for Status

Status indicators are common in health dashboards, showing things like "Normal," "High," or "Active." A Pill component is perfect for this.

What we're doing

We'll create a small, pill-shaped component that changes color based on a variant prop.

Implementation

Create the component file at src/components/Pill.tsx:

code
// src/components/Pill.tsx
import React from 'react';

export interface PillProps {
  text: string;
  variant?: 'success' | 'warning' | 'danger' | 'info';
}

export const Pill: React.FC<PillProps> = ({ text, variant = 'info' }) => {
  const baseClasses = 'inline-block px-3 py-1 text-xs font-semibold rounded-full';
  
  const variantClasses = {
    success: 'bg-green-100 text-green-800',
    warning: 'bg-yellow-100 text-yellow-800',
    danger: 'bg-red-100 text-red-800',
    info: 'bg-blue-100 text-blue-800',
  };

  return (
    <span className={`${baseClasses} ${variantClasses[variant]}`}>
      {text}
    </span>
  );
};
Code collapsed

How it works

This component uses a variantClasses object to map the variant prop to specific Tailwind CSS classes. This is a clean way to handle conditional styling within a component.

Creating the Story

Now for the story at src/components/Pill.stories.tsx:

code
// src/components/Pill.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Pill } from './Pill';

const meta: Meta<typeof Pill> = {
  title: 'Dashboard/Pill',
  component: Pill,
  tags: ['autodocs'],
  argTypes: {
    text: { control: 'text' },
    variant: {
      control: { type: 'select' },
      options: ['success', 'warning', 'danger', 'info'],
    },
  },
};

export default meta;
type Story = StoryObj<typeof Pill>;

export const Success: Story = {
  args: {
    text: 'Normal',
    variant: 'success',
  },
};

export const Warning: Story = {
  args: {
    text: 'Elevated',
    variant: 'warning',
  },
};

export const Danger: Story = {
  args: {
    text: 'High',
    variant: 'danger',
  },
};
Code collapsed

Check your running Storybook instance, and you'll find your new Pill component, complete with a dropdown to test its different variants.

Putting It All Together: A Dashboard View

Let's create a simple story that combines our components to simulate a small section of a health dashboard.

Create a new story file src/stories/HealthDashboard.stories.tsx:

code
// src/stories/HealthDashboard.stories.tsx
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { MetricCard } from '../components/MetricCard';
import { Pill } from '../components/Pill';

const DashboardView = () => (
  <div className="p-8 bg-gray-50 min-h-screen">
    <h1 className="text-3xl font-bold text-gray-800 mb-2">Patient Vitals</h1>
    <div className="flex items-center space-x-2 mb-8">
      <Pill text="Live" variant="success" />
      <Pill text="Monitoring Active" variant="info" />
    </div>
    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
      <MetricCard label="Heart Rate" value="72" unit="bpm" />
      <MetricCard label="Blood Pressure" value="120/80" unit="mmHg" />
      <MetricCard label="Oxygen Saturation" value="98" unit="%" />
      <MetricCard label="Temperature" value="36.6" unit="°C" />
    </div>
  </div>
);

const meta: Meta = {
  title: 'Pages/HealthDashboard',
  component: DashboardView,
};

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {};
Code collapsed

This story shows how easily you can compose more complex UIs from your simple, isolated components. This is the core power of building a component library.

Production Deployment: Bundling Your Library

When you're ready to share your library, you need to bundle it into a distributable format. We can configure Vite for this.

Modify your vite.config.ts to enable "library mode":

code
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'
import dts from 'vite-plugin-dts'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react(), dts()], // dts plugin for generating type definitions
  build: {
    lib: {
      entry: resolve(__dirname, 'src/index.ts'), // Your library's entry point
      name: 'HealthDashboardLibrary',
      fileName: 'health-dashboard-library',
    },
    rollupOptions: {
      external: ['react', 'react-dom'], // Don't bundle React
      output: {
        globals: {
          react: 'React',
          'react-dom': 'ReactDOM',
        },
      },
    },
  },
})
Code collapsed

You'll also need an entry point file, src/index.ts, that exports all your components:

code
// src/index.ts
export * from './components/MetricCard';
export * from './components/Pill';
Code collapsed

Now, when you run npm run build, Vite will create a dist folder with your bundled JavaScript and CSS files, ready to be published to npm or a private registry.

Conclusion

We've successfully set up a modern frontend project for creating a component library with React, Storybook, and Tailwind CSS. We built two essential dashboard components, documented them in Storybook, and configured our project to bundle the library for production use.

This foundation is incredibly powerful. You can now:

  • Expand the library with more complex components like charts, tables, and navigation elements.
  • Implement a theming system using Tailwind's configuration to easily change colors, fonts, and spacing.
  • Publish your library to npm, making it a reusable package for your entire organization.

Building a component library is an investment that pays huge dividends in development speed, consistency, and maintainability.

Resources

#

Article Tags

reactstorybooktailwindcssfrontendhealthtech
W

WellAlly's core development team, comprised of healthcare professionals, software engineers, and UX designers committed to revolutionizing digital health management.

Expertise

Healthcare TechnologySoftware DevelopmentUser ExperienceAI & Machine Learning

Found this article helpful?

Try KangXinBan and start your health management journey

© 2024 康心伴 WellAlly · Professional Health Management