@metalbear/ui
v0.2.5
Published
MetalBear Design System - React component library
Readme
@metalbear/ui
MetalBear Design System - A React component library built with Radix UI primitives and Tailwind CSS.
Features
- 30+ accessible components built on Radix UI
- App primitives: theming, toasts, clipboard, error boundaries, empty states, chart colors
- Shared strictness contract: exported TypeScript and ESLint base configs for every MetalBear frontend
- Styled with Tailwind CSS, with an exported preset
- Full TypeScript support
- Light and dark mode theming
- Storybook documentation with a11y checks
- Tree-shakeable ESM and CJS builds with externalized dependencies
Installation
pnpm add @metalbear/uiPeer Dependencies
Make sure you have React 18 or 19 installed:
pnpm add react react-domUsage
Import components and styles in your app:
import { Button, Card, Input } from '@metalbear/ui'
import '@metalbear/ui/styles.css'
function App() {
return (
<Card>
<Input placeholder="Enter your name" />
<Button>Submit</Button>
</Card>
)
}Shared Configs
Consumers should extend the exported bases instead of maintaining their own:
TypeScript (maximal strictness):
// tsconfig.json
{
"extends": "@metalbear/ui/tsconfig.base.json"
}ESLint (type-checked strict tier + jsx-a11y):
// eslint.config.js
import base from '@metalbear/ui/eslint-base'
export default [...base]Tailwind (brand theme):
// tailwind.config.js
module.exports = {
presets: [require('@metalbear/ui/tailwind-preset')],
}Available Components
Form Components
Button- Primary action buttons with variantsInput- Text input fieldSearchInput- Input with search affordancesTextarea- Multi-line text inputCheckbox- Boolean selectionRadioGroup- Single selection from optionsSelect- Dropdown selectionSwitch- Toggle boolean stateLabel- Accessible form labels
Layout Components
Card- Content container with header/footerDataCard- Metric/stat display cardTable- Data table with resizable columns (mouse + keyboard)Tabs- Tabbed content navigationAccordion- Collapsible sectionsSeparator- Visual dividerBreadcrumbs- Navigation trailNavigationMenu- Site navigationCarousel- Scrollable content
Overlay Components
Dialog- Modal dialogPopover- Anchored floating contentTooltip- Hover information display
Feedback Components
Badge- Status indicatorLoader- Loading spinnerToast/Toaster- Notifications (with theuseToasthook)EmptyState- Empty and error placeholdersErrorBoundary- Render-error containmentCode- Inline and block code display
App Primitives
ThemeProvider/useTheme- Light/dark/system theming with pluggable storageuseToast/toast- Imperative notificationsCopyButton/useClipboard- Copy-to-clipboard with feedbackchartColors- Brand chart palettes for light/dark (getChartColors,getTooltipStyle)
Development Setup
Prerequisites
- Node.js >= 20.11 (see
.nvmrc) - pnpm 10 (pinned via
packageManager, usecorepack enable pnpm)
Quick Start
# Clone the repository
git clone https://github.com/metalbear-co/ui.git
cd ui
# Install dependencies
pnpm install
# Start Storybook development server
pnpm devStorybook will be available at http://localhost:6006
Available Scripts
| Command | Description |
| ------------------------------ | ------------------------------------------------------ |
| pnpm dev | Start Storybook dev server |
| pnpm build | Build the library for production |
| pnpm build:storybook | Build static Storybook site |
| pnpm test | Run the vitest suite (unit + story render smoke) |
| pnpm typecheck | Run TypeScript type checking |
| pnpm lint | Run ESLint (type-checked strict tier + jsx-a11y) |
| pnpm format | Format code with Prettier |
| pnpm format:check | Check code formatting |
| bash scripts/contract-test.sh| Verify the published package contract against a fixture consumer |
Project Structure
ui/
├── .husky/ # Git hooks
├── .storybook/ # Storybook configuration
├── contract/ # Consumer fixture for the contract test
├── scripts/ # contract-test.sh
├── src/
│ ├── components/ # React components
│ │ ├── Button/
│ │ │ ├── Button.tsx
│ │ │ ├── Button.stories.tsx
│ │ │ └── index.ts
│ │ └── ...
│ ├── hooks/ # useToast, useClipboard
│ ├── lib/ # cn helper, chartColors
│ ├── styles/
│ │ └── globals.css # CSS variables and Tailwind
│ ├── test/ # vitest setup and story smoke test
│ └── index.ts # Main exports
├── eslint-base.js # Exported ESLint base for consumers
├── tsconfig.base.json # Exported strict tsconfig for consumers
├── tailwind-preset.cjs # Exported Tailwind preset for consumers
├── package.json
├── tailwind.config.js
├── tsconfig.json
├── vite.config.ts
└── vitest.config.tsAdding a New Component
- Create a new folder in
src/components/ - Add the component file (e.g.,
MyComponent.tsx) - Add stories (e.g.,
MyComponent.stories.tsx) - Add barrel export (
index.ts) - Export from
src/components/index.ts - Add tests for any stateful logic (the story smoke test covers rendering automatically)
Theming
The design system uses CSS variables for theming. Override these in your app:
:root {
--primary: 244 85% 69%; /* Main Purple */
--secondary: 38 100% 74%; /* Yellow */
--background: 240 43% 99%; /* Light Grey */
--foreground: 0 0% 0%; /* Black */
--destructive: 359 85% 68%; /* Blush Red */
}
.dark {
--background: 243 33% 19%; /* Dark Purple */
--foreground: 240 43% 99%; /* Light Grey */
}For runtime theme switching, use ThemeProvider and useTheme instead of hand-rolling a theme context.
Brand Colors
| Color | Hex | Usage |
| ------------- | --------- | ----------------------------- |
| Main Purple | #756DF3 | Primary actions, backgrounds |
| Yellow | #FFCB7D | Highlights, secondary actions |
| Medium Purple | #E4E3FD | Muted elements |
| Dark Purple | #232141 | Dark mode background |
| Light Grey | #FAFAFD | Light mode background |
| Blush Red | #F36869 | Destructive actions |
CI and Publishing
Every PR must pass two required checks:
- check: lint, format, typecheck, tests, library build, Storybook build
- contract: packs the built tarball, installs it into the fixture app under
contract/, and verifies the consumer surface (types undertsconfig.base.json, linting witheslint-base, the Tailwind preset)
Publishing is automatic. To release:
- Bump
versioninpackage.jsonin your PR - Merge to main
The publish workflow re-runs checks and the contract test, publishes to npm only when the version is not already published, and tags the release (vX.Y.Z). Never run pnpm publish manually. Storybook deploys to GitHub Pages on every main push.
Dependencies are kept fresh by Dependabot (monthly, minor/patch grouped).
