A themeable, accessible React component library built with Tailwind CSS 4.
- 🎨 Fully Themeable - Customize colors, fonts, border radius, and more using CSS variables
- 🏢 Multi-Brand Support - Pre-configured themes for BlueHive, Enterprise Health, WebChart, Waggleline, and MIE
- ♿ Accessible - Built with WCAG guidelines in mind, including proper ARIA attributes and keyboard navigation
- 🌳 Tree-Shakeable - Import only the components you need
- 🌙 Dark Mode - Built-in dark mode support with system preference detection
- 📦 Dual Format - ESM and CommonJS support
- 🎯 TypeScript - Full TypeScript support with comprehensive type definitions
- 📚 Storybook - Interactive documentation and component playground
- Installation
- Quick Start
- Development
- Storybook
- Using in Other Projects
- Brand System
- Theming
- Components
- Hooks
- Utilities
- Releases
- Contributing
npm install @mieweb/ui
# or
yarn add @mieweb/ui
# or
pnpm add @mieweb/uiThis library requires React 18+ and React DOM 18+:
npm install react react-domIf your project uses Tailwind CSS 4, you can use the library's Tailwind preset for the best experience:
- Add the preset to your
tailwind.config.js:
// tailwind.config.js
module.exports = {
presets: [require('@mieweb/ui/tailwind-preset')],
content: [
// ... your content
'./node_modules/@mieweb/ui/dist/**/*.js',
],
// Override theme values to match your brand
theme: {
extend: {
colors: {
primary: {
500: '#your-brand-color',
},
},
},
},
};- Import and use components:
import { Button, Card, Input } from '@mieweb/ui';
function App() {
return (
<Card>
<Input label="Email" type="email" />
<Button>Submit</Button>
</Card>
);
}If you're not using Tailwind CSS, you can import the pre-compiled stylesheet:
import '@mieweb/ui/styles.css';
import { Button } from '@mieweb/ui';- Clone the repository:
git clone https://github.com/mieweb/ui.git
cd ui- Install dependencies:
npm install- Start development mode:
npm run devThis will watch for changes and rebuild the library automatically.
| Script | Description |
|---|---|
npm run dev |
Start development mode with watch |
npm run build |
Build the library for production |
npm run storybook |
Start Storybook development server |
npm run build-storybook |
Build Storybook for static hosting |
npm run typecheck |
Run TypeScript type checking |
npm run lint |
Run ESLint |
npm run lint:fix |
Run ESLint with auto-fix |
npm run format |
Check code formatting with Prettier |
npm run format:fix |
Fix code formatting with Prettier |
npm run test |
Run tests |
npm run test:watch |
Run tests in watch mode |
Storybook provides interactive documentation and a component playground where you can explore all components with different props and themes.
npm run storybookThis starts the Storybook development server at http://localhost:6006.
- Component Explorer: Browse all components with live examples
- Props Documentation: See all available props for each component
- Theme Switcher: Toggle between light and dark modes
- Brand Switcher: Preview components with different brand themes (BlueHive, Enterprise Health, WebChart, Waggleline, MIE)
- Accessibility Panel: Check accessibility compliance for each component
- Controls: Interactively modify component props
To build a static version of Storybook for deployment:
npm run build-storybookThe output will be in the storybook-static directory.
Once published, install the package in your project:
npm install @mieweb/uiThen import components:
import { Button, Card, Input, ThemeProvider } from '@mieweb/ui';
import '@mieweb/ui/styles.css'; // or use a brand CSS file
function App() {
return (
<ThemeProvider>
<Card>
<Card.Header>
<Card.Title>Welcome</Card.Title>
</Card.Header>
<Card.Content>
<Input label="Email" type="email" placeholder="you@example.com" />
<Button className="mt-4">Submit</Button>
</Card.Content>
</Card>
</ThemeProvider>
);
}For local development across projects:
- In the @mieweb/ui directory:
cd /path/to/mieweb-ui
npm run build
npm link- In your consuming project:
cd /path/to/your-project
npm link @mieweb/ui- Import and use components:
import { Button } from '@mieweb/ui';
import '@mieweb/ui/dist/styles.css';For monorepo setups or when you want to reference the source directly:
// In your consuming project's package.json
{
"dependencies": {
"@mieweb/ui": "file:../mieweb-ui"
}
}Then run npm install and import as usual.
// app/layout.tsx or pages/_app.tsx
import '@mieweb/ui/brands/bluehive.css';
import { ThemeProvider } from '@mieweb/ui';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<ThemeProvider>{children}</ThemeProvider>
</body>
</html>
);
}// main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import '@mieweb/ui/brands/enterprise-health.css';
import { ThemeProvider } from '@mieweb/ui';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<ThemeProvider>
<App />
</ThemeProvider>
</React.StrictMode>
);// client/main.tsx
import { Meteor } from 'meteor/meteor';
import React from 'react';
import { createRoot } from 'react-dom/client';
import '@mieweb/ui/brands/bluehive.css';
import { ThemeProvider } from '@mieweb/ui';
import App from '/imports/ui/App';
Meteor.startup(() => {
const container = document.getElementById('react-target');
const root = createRoot(container!);
root.render(
<ThemeProvider>
<App />
</ThemeProvider>
);
});The library includes pre-configured themes for multiple brands. Each brand has its own design system with unique colors, typography, border radius, and shadows.
| Brand | Primary Color | Font | Description |
|---|---|---|---|
| BlueHive | #27AAE1 (Blue) |
Nunito | DOT Physical scheduling and healthcare compliance |
| Enterprise Health | #6E2B68 (Burgundy) |
Jost | Employee health and occupational medicine |
| WebChart | #F5841F (Orange) |
Inter | Future-ready electronic health record system |
| Waggleline | #17AEED (Blue) |
Inter | Experience visualization and orchestration |
| MIE | #27AE60 (Green) |
Inter | Healthcare software and services |
// Import the brand's CSS file
import '@mieweb/ui/brands/enterprise-health.css';
import { Button, Card } from '@mieweb/ui';import { ThemeProvider } from '@mieweb/ui';
import { enterpriseHealthBrand } from '@mieweb/ui/brands';
function App() {
return (
<ThemeProvider brand={enterpriseHealthBrand}>
<YourApp />
</ThemeProvider>
);
}// tailwind.config.js
const { enterpriseHealthBrand } = require('@mieweb/ui/brands');
const { createBrandPreset } = require('@mieweb/ui/brands/types');
module.exports = {
presets: [createBrandPreset(enterpriseHealthBrand)],
// ...
};Each brand defines the following design tokens:
Extracted from enterprisehealth.com:
/* Primary: Burgundy/Purple */
--mieweb-primary-600: #6e2b68;
/* Secondary: Deep Teal Blue (for gradients) */
--mieweb-secondary: #00497a;
/* Accent: Gold/Yellow (logo) */
--mieweb-accent: #f8b700;
/* Brand Gradient */
--mieweb-gradient: linear-gradient(111.02deg, #00497a, #6e2b68);
/* Typography */
--mieweb-font-sans: 'Jost', ui-sans-serif, system-ui, sans-serif;
/* Border Radius (larger, more rounded) */
--mieweb-radius-sm: 0.375rem; /* 6px - badges */
--mieweb-radius-md: 0.625rem; /* 10px - buttons */
--mieweb-radius-lg: 0.75rem; /* 12px - inputs */
--mieweb-radius-2xl: 1.5rem; /* 24px - cards */
/* Shadows (subtle, layered) */
--mieweb-shadow-card:
0 16px 32px 0 rgba(34, 35, 38, 0.05), 0 8px 16px 0 rgba(34, 35, 38, 0.05);/* Primary: Blue */
--mieweb-primary-500: #27aae1;
/* Typography */
--mieweb-font-sans: 'Nunito', ui-sans-serif, system-ui, sans-serif;You can create your own brand configuration:
import type { BrandConfig } from '@mieweb/ui/brands/types';
export const myBrand: BrandConfig = {
name: 'my-brand',
displayName: 'My Brand',
description: 'Custom brand for my application',
colors: {
primary: {
50: '#f0f9ff',
// ... full color scale 50-950
600: '#0284c7', // Main brand color
// ...
},
light: {
background: '#ffffff',
foreground: '#171717',
// ... semantic colors
},
dark: {
background: '#171717',
foreground: '#fafafa',
// ... semantic colors
},
},
typography: {
fontFamily: {
sans: ['Your Font', 'ui-sans-serif', 'system-ui', 'sans-serif'],
mono: ['ui-monospace', 'SFMono-Regular', 'Menlo', 'monospace'],
},
},
borderRadius: {
none: '0',
sm: '0.25rem',
md: '0.5rem',
lg: '0.75rem',
xl: '1rem',
'2xl': '1.5rem',
full: '9999px',
},
boxShadow: {
card: '0 1px 3px 0 rgb(0 0 0 / 0.1)',
dropdown: '0 4px 6px -1px rgb(0 0 0 / 0.1)',
modal: '0 10px 15px -3px rgb(0 0 0 / 0.1)',
},
};The library uses CSS custom properties for theming. Override these variables to customize the appearance:
:root {
/* Primary color scale */
--mieweb-primary-500: #27aae1;
/* Semantic colors */
--mieweb-background: hsl(0 0% 100%);
--mieweb-foreground: hsl(222.2 84% 4.9%);
/* Border radius */
--mieweb-radius-md: 0.5rem;
/* Font */
--mieweb-font-sans: 'Your Font', sans-serif;
}The library supports dark mode via the .dark class or data-theme="dark" attribute on a parent element:
import { ThemeProvider, useThemeContext, Button } from '@mieweb/ui';
function ThemeToggle() {
const { resolvedTheme, setTheme } = useThemeContext();
return (
<Button
onClick={() => setTheme(resolvedTheme === 'dark' ? 'light' : 'dark')}
>
Toggle Theme
</Button>
);
}
function App() {
return (
<ThemeProvider>
<ThemeToggle />
</ThemeProvider>
);
}Button- Multi-variant button with loading stateInput- Text input with label, error, and helper textCard- Container component with header, content, and footerText- Typography component with variantsBadge- Status indicators and labelsAlert- Feedback messages
PhoneInput- US phone number formattingDateInput- Date input with validation modes (DOB, expiration, etc.)
Tooltip- Accessible tooltip with multiple placementsDropdown- Dropdown menu with items, separators, and labels
VisuallyHidden- Screen reader only contentThemeProvider- Theme context provider
useTheme()- Theme state managementuseClickOutside()- Detect clicks outside an elementuseEscapeKey()- Handle escape key pressuseFocusTrap()- Trap focus within a containerusePrefersReducedMotion()- Detect reduced motion preference
import { cn } from '@mieweb/ui/utils';
// Merge classes with Tailwind conflict resolution
cn('px-4 py-2', isActive && 'bg-primary-500', className);import { formatPhoneNumber, isValidPhoneNumber } from '@mieweb/ui/utils';
formatPhoneNumber('5551234567'); // "(555) 123-4567"
isValidPhoneNumber('5551234567'); // trueimport { formatDateValue, calculateAge, isValidDate } from '@mieweb/ui/utils';
formatDateValue('01152024'); // "01/15/2024"
calculateAge('01/15/1990'); // 34
isValidDate('01/15/2024'); // trueImport components directly for optimal bundle size:
// Import only what you need
import { Button } from '@mieweb/ui/components/Button';
import { useTheme } from '@mieweb/ui/hooks';
import { cn } from '@mieweb/ui/utils';All components are fully typed. Import types as needed:
import type { ButtonProps, InputProps, Theme } from '@mieweb/ui';This package uses automated releases via GitHub Actions. There are two release channels:
| Channel | npm Tag | Install Command | Description |
|---|---|---|---|
| Stable | latest |
npm install @mieweb/ui |
Production-ready releases |
| Prerelease | next |
npm install @mieweb/ui@next |
Latest from main branch |
Every push to the main branch automatically publishes a prerelease version to npm:
- Version format:
x.y.z-dev.{run_number}(e.g.,0.1.0-dev.45) - npm tag:
next - Install:
npm install @mieweb/ui@next
This allows consumers to test the latest changes before a stable release.
To create a stable release:
- Go to the repository on GitHub
- Navigate to Actions → Create Stable Release
- Click Run workflow
- Select the version bump type:
patch- Bug fixes (0.1.0 → 0.1.1)minor- New features (0.1.0 → 0.2.0)major- Breaking changes (0.1.0 → 1.0.0)
- Click Run workflow
The workflow will:
- Bump the version in
package.json - Commit and push the change
- Create a git tag (e.g.,
v0.2.0) - Trigger the release workflow which publishes to npm and creates a GitHub Release
You can also create a release by pushing a version tag directly:
# Create and push a tag
git tag v1.0.0
git push origin v1.0.0The release workflow will automatically:
- Run tests and build
- Publish to npm with the appropriate tag (
latestfor stable,nextfor prereleases likev1.0.0-beta.1) - Create a GitHub Release with auto-generated release notes
We follow Semantic Versioning:
- MAJOR version for incompatible API changes
- MINOR version for backwards-compatible functionality additions
- PATCH version for backwards-compatible bug fixes
We welcome contributions! Here's how to get started:
- Fork and clone the repository
- Install dependencies:
npm install - Create a branch:
git checkout -b feature/your-feature - Start Storybook:
npm run storybook - Make your changes
- Run checks:
npm run typecheck # TypeScript npm run lint # ESLint npm run format # Prettier npm run test # Tests
- Commit your changes following Conventional Commits
- Push and create a Pull Request
- Create a new directory in
src/components/YourComponent/ - Add the component file:
YourComponent.tsx - Add the index export:
index.ts - Add Storybook stories:
YourComponent.stories.tsx - Export from
src/components/index.ts - Add to the README components list
- Create
src/brands/your-brand.tswith theBrandConfig - Create
src/brands/your-brand.csswith CSS variables - Export from
src/brands/index.ts - Add to the README brands table
Copyright © 2026 Medical Informatics Engineering, Inc. All rights reserved.
This software is source available with the following terms:
- ✅ Free for open source projects - Use, modify, and distribute freely in open source projects with attribution
- ✅ Free for non-commercial use - Personal projects, education, research
- 💼 Commercial license required - For proprietary products or commercial use, contact licensing@mieweb.com
See the LICENSE file for full details.