huda-ui
v1.1.0
Published
A professional React UI component library for non-designers
Maintainers
Readme
huda-ui
A professional React UI component library with 120+ components, a token-driven design system, and built-in dark mode support. Zero external dependencies beyond React and Emotion.
Features
- 120+ production-ready components — from basic primitives to complex data visualizations
- Token-driven theming — change one file to re-skin your entire app
- Dark mode — built-in light/dark mode with
useColorMode() - TypeScript-first — full type safety with exported types for every component
- Tree-shakable — named exports only,
sideEffects: false - Responsive —
ResponsiveValue<T>prop system with{ base, sm, md, lg, xl }breakpoints - Polymorphic — layout components accept an
asprop to render as any HTML element - Figma-compatible — import Figma tokens directly with
adaptFigmaTokens() - Lightweight — no external UI dependencies, just React + Emotion
Installation
npm install huda-ui @emotion/react @emotion/styledQuick Start
import { TokensProvider, Button, Card, Text } from 'huda-ui';
function App() {
return (
<TokensProvider>
<Card>
<Text>Hello from huda-ui</Text>
<Button variant="solid" colorScheme="primary">
Get Started
</Button>
</Card>
</TokensProvider>
);
}Theming
Token-Driven Design
huda-ui uses a design token system. Tokens define your brand's colors, typography, spacing, radii, shadows, and more. Change one token file — every component updates automatically.
import { TokensProvider } from 'huda-ui';
import type { DesignTokens } from 'huda-ui';
const myTokens: DesignTokens = {
colors: {
primary: {
50: '#EEF2FF', 100: '#E0E7FF', 200: '#C7D2FE',
300: '#A5B4FC', 400: '#818CF8', 500: '#6366F1',
600: '#4F46E5', 700: '#4338CA', 800: '#3730A3', 900: '#312E81',
},
neutral: { /* 50–900 gray scale */ },
error: { /* 50–900 red scale */ },
success: { /* 50–900 green scale */ },
warning: { /* 50–900 yellow scale */ },
info: { /* 50–900 blue scale */ },
white: '#FFFFFF',
black: '#000000',
light: {
background: '#FFFFFF',
surface: '#F9FAFB',
text: '#111827',
textSecondary: '#6B7280',
border: '#E5E7EB',
focus: '#6366F1',
},
dark: {
background: '#111827',
surface: '#1F2937',
text: '#F9FAFB',
textSecondary: '#9CA3AF',
border: '#374151',
focus: '#818CF8',
},
},
typography: {
fontFamily: '"Inter", sans-serif',
fontFamilyMono: '"Fira Code", monospace',
fontSizes: { xs: '0.75rem', sm: '0.875rem', md: '1rem', lg: '1.125rem', xl: '1.25rem', '2xl': '1.5rem', '3xl': '2rem', '4xl': '2.5rem', '5xl': '3.25rem' },
fontWeights: { normal: 400, medium: 500, semibold: 600, bold: 700 },
lineHeights: { tight: 1.2, normal: 1.5, relaxed: 1.8 },
},
spacing: { 0: '0px', 1: '4px', 2: '8px', 3: '12px', 4: '16px', 5: '20px', 6: '24px', 8: '32px', 10: '40px', 12: '48px', 16: '64px', 20: '80px', 24: '96px' },
radii: { none: '0px', sm: '4px', md: '8px', lg: '12px', xl: '16px', full: '9999px' },
shadows: {
light: { none: 'none', sm: '0 1px 2px rgba(0,0,0,0.05)', md: '0 4px 6px rgba(0,0,0,0.07)', lg: '0 10px 15px rgba(0,0,0,0.1)', xl: '0 20px 25px rgba(0,0,0,0.1)' },
dark: { none: 'none', sm: '0 1px 2px rgba(0,0,0,0.3)', md: '0 4px 6px rgba(0,0,0,0.4)', lg: '0 10px 15px rgba(0,0,0,0.5)', xl: '0 20px 25px rgba(0,0,0,0.6)' },
},
borderWidth: { none: '0px', thin: '1px', default: '2px', thick: '4px' },
transitions: { fast: '120ms ease-out', normal: '200ms ease-out', slow: '350ms ease-out' },
breakpoints: { sm: '640px', md: '768px', lg: '1024px', xl: '1280px' },
zIndices: { base: 0, dropdown: 1000, sticky: 1100, overlay: 1300, modal: 1400, toast: 1500 },
};
function App() {
return (
<TokensProvider tokens={myTokens} defaultColorMode="light">
{/* Your app */}
</TokensProvider>
);
}Partial Tokens
You don't have to provide every value. Pass a partial object and missing keys fall back to sensible defaults:
<TokensProvider tokens={{ colors: { primary: myPrimaryScale } }}>
{/* Everything else uses defaults */}
</TokensProvider>Token Validation
Tokens are validated at runtime in development mode. Use useTokens() to access validation results:
import { useTokens } from 'huda-ui';
function DebugPanel() {
const { tokens, validation } = useTokens();
if (!validation.ok) {
console.log(validation.errors); // string[]
console.log(validation.warnings); // string[]
}
return <pre>{JSON.stringify(tokens, null, 2)}</pre>;
}Figma Token Adaptation
Import tokens directly from Figma using Tokens Studio, W3C Design Tokens, or flat key formats:
import { adaptFigmaTokens, TokensProvider } from 'huda-ui';
import rawFigma from './figma-export.json';
const tokens = adaptFigmaTokens(rawFigma);
function App() {
return (
<TokensProvider tokens={tokens}>
{/* Figma tokens driving every component */}
</TokensProvider>
);
}Supported formats:
- Tokens Studio —
{ value: "#6366F1" } - W3C Design Tokens —
{ $value: "#6366F1" } - Flat keys —
{ "primary-500": "#6366F1" }
Dark Mode
import { useColorMode } from 'huda-ui';
function ThemeToggle() {
const { colorMode, toggleColorMode } = useColorMode();
return (
<button onClick={toggleColorMode}>
Current: {colorMode}
</button>
);
}Components
Core (14)
| Component | Description |
|-----------|-------------|
| Box | Polymorphic base layout primitive |
| Flex | Flexbox container with shorthand props |
| Stack | Vertical/horizontal stack with spacing |
| Text | Text rendering with typography tokens |
| Heading | Semantic heading (h1–h6) |
| Label | Form label with required indicator |
| Icon | SVG icon wrapper with sizing |
| Button | Button with variants, sizes, loading state |
| IconButton | Icon-only button |
| Spinner | Loading spinner |
| Card | Card container with Header, Body, Footer |
| Badge | Status badge with color schemes |
| Avatar | User avatar with fallback initials |
| Divider | Horizontal/vertical divider |
Layout (8)
| Component | Description |
|-----------|-------------|
| Grid | CSS Grid with responsive columns |
| SimpleGrid | Auto-responsive grid |
| Container | Max-width content container |
| Center | Center children horizontally and vertically |
| Wrap | Flex wrap with gap |
| Spacer | Flexible spacer for flex layouts |
| AspectRatio | Maintain aspect ratio |
| Show / Hide | Responsive visibility |
Form (17)
| Component | Description |
|-----------|-------------|
| FormControl | Form field wrapper with label, error, helper |
| FormGroup | Group related form fields |
| Form | Form wrapper with spacing |
| FormField | Label + input + error combo |
| FormError | Error message display |
| FormHelperText | Helper text below inputs |
| Input | Text input with variants and sizes |
| Textarea | Multi-line text input |
| Select | Dropdown select |
| MultiSelect | Multi-value select with tags |
| Checkbox | Checkbox with label |
| Radio / RadioGroup | Radio buttons |
| Switch | Toggle switch |
| Slider | Range slider |
| DatePicker | Date selection |
| TimePicker | Time selection |
| DateTimePicker | Combined date + time picker |
| OTPInput | OTP/PIN code input |
Navigation (7)
| Component | Description |
|-----------|-------------|
| Tabs | Tab navigation with panels |
| Breadcrumb | Breadcrumb navigation |
| Pagination | Page navigation |
| Navbar | Top navigation bar |
| Sidebar | Collapsible side navigation |
| Menu | Dropdown menu |
| BottomNavigation | Mobile bottom tab bar |
Feedback (17)
| Component | Description |
|-----------|-------------|
| Modal | Modal dialog with Header, Body, Footer |
| Drawer | Slide-in panel |
| Dialog | Confirmation dialog |
| Alert | Inline alert messages |
| ToastProvider / useToast | Toast notifications |
| Snackbar | Bottom snackbar |
| Notification | Notification card |
| Tooltip | Hover tooltip |
| Progress | Progress bar |
| ProgressBar | Standalone progress bar |
| ProgressCircle | Circular progress |
| Skeleton | Content loading placeholder |
| SkeletonText | Text loading placeholder |
| SkeletonCircle | Circle loading placeholder |
| EmptyState | Empty state with icon and action |
| ErrorState | Error state display |
| NoDataState | No data available state |
Data Display (14)
| Component | Description |
|-----------|-------------|
| Table | Data table with sorting |
| DataTable | Full-featured data table |
| Accordion | Expandable sections |
| Tag | Removable tag/chip |
| Image | Image with fallback |
| Link | Styled anchor |
| Code | Inline/block code |
| Kbd | Keyboard shortcut display |
| List | Ordered/unordered lists |
| Timeline | Vertical timeline |
| Stat | Statistic display with trend |
| Carousel | Image/content carousel |
| Calendar | Calendar display |
| EventCard | Event card with date/time |
Overlay (5)
| Component | Description |
|-----------|-------------|
| Popover | Click-triggered popover |
| ContextMenu | Right-click context menu |
| HoverCard | Hover-triggered card |
| ActionSheet | Mobile action sheet |
| BottomSheet | Draggable bottom sheet |
Layout Templates (11)
| Component | Description |
|-----------|-------------|
| PageLayout | Full page layout structure |
| AuthLayout | Authentication page layout |
| DashboardLayout | Dashboard with sidebar |
| Section | Content section |
| Header | Page header |
| Footer | Page footer |
| Content | Content area with max-width |
| Page | Full page wrapper |
| AppLayout | App shell layout |
| SidebarLayout | Sidebar + content layout |
Advanced (13)
| Component | Description |
|-----------|-------------|
| SearchBar | Search input with suggestions |
| CommandPalette | Command palette (Cmd+K) |
| FileUpload | File upload with drag-and-drop |
| Stepper | Multi-step wizard |
| KeyboardShortcutHint | Keyboard shortcut display |
| ThemeSwitcher | Light/dark/system theme toggle |
| LanguageSwitcher | Language/locale selector |
| UserMenu | User avatar dropdown menu |
| NotificationCenter | Notification list panel |
| RichTextEditor | Rich text editor |
| MediaViewer | Image/video viewer |
| SettingsPanel | Settings form panel |
| PermissionsGuard / RoleGuard | Permission-based rendering |
Auth Forms (4)
| Component | Description |
|-----------|-------------|
| LoginForm | Login form with validation |
| RegisterForm | Registration form |
| ForgotPasswordForm | Forgot password form |
| ResetPasswordForm | Password reset form |
Interactive (5)
| Component | Description |
|-----------|-------------|
| LocationPicker | Location coordinate picker |
| DragAndDrop | Drag and drop container |
| ResizablePanel | Resizable panel |
| InfiniteScroll | Infinite scroll wrapper |
| VirtualizedList | Virtualized list for large datasets |
Data Visualization (8)
| Component | Description |
|-----------|-------------|
| CalendarView | Calendar with month/week/day views |
| Charts | Chart wrapper |
| LineChart | Line chart |
| BarChart | Bar chart |
| PieChart | Pie chart |
| AreaChart | Area chart |
| ChartContainer | Chart container with title/legend |
| MapView | Map display with markers |
Utility (3)
| Component | Description |
|-----------|-------------|
| Portal | Render children in a portal |
| VisuallyHidden | Accessible hidden content |
| CloseButton | Close/dismiss button |
Hooks
| Hook | Description |
|------|-------------|
| useTheme() | Access the current resolved theme |
| useColorMode() | Get/set color mode (light/dark) |
| useTokens() | Access design tokens and validation |
| useBreakpoint() | Current active breakpoint |
| useBreakpointValue() | Responsive value based on breakpoint |
| useDisclosure() | Open/close state management |
| useDebounce() | Debounced value |
| useDebouncedCallback() | Debounced callback function |
| useModal() | Modal state management |
| useForm() | Form state, validation, and submission |
| useToast() | Trigger toast notifications |
| usePermissions() | Access permissions context |
Responsive Props
Layout components support responsive values:
<Box
padding={{ base: '16px', md: '32px', xl: '48px' }}
display={{ base: 'block', lg: 'flex' }}
>
<Text fontSize={{ base: 'sm', md: 'lg' }}>
Responsive text
</Text>
</Box>Compound Components
Several components use the compound component pattern:
<Card variant="outlined">
<Card.Header>Title</Card.Header>
<Card.Body>Content</Card.Body>
<Card.Footer>Actions</Card.Footer>
</Card>
<Modal isOpen={isOpen} onClose={onClose}>
<Modal.Header>Confirm</Modal.Header>
<Modal.Body>Are you sure?</Modal.Body>
<Modal.Footer>
<Button onClick={onClose}>Cancel</Button>
<Button variant="solid">Confirm</Button>
</Modal.Footer>
</Modal>
<Tabs defaultIndex={0}>
<Tabs.List>
<Tabs.Tab>Tab 1</Tabs.Tab>
<Tabs.Tab>Tab 2</Tabs.Tab>
</Tabs.List>
<Tabs.Panel>Panel 1</Tabs.Panel>
<Tabs.Panel>Panel 2</Tabs.Panel>
</Tabs>Polymorphic as Prop
Layout components can render as any HTML element:
<Box as="section" padding="16px">
<Text as="label" htmlFor="name">Name</Text>
<Stack as="nav" direction="horizontal">
<Link as="a" href="/home">Home</Link>
</Stack>
</Box>Template
The template/ directory includes a ready-to-use app template that demonstrates token-driven theming:
template/
src/
design-tokens/
tokens.ts ← Swap this one line to re-skin
tokens.default.ts ← Default indigo theme
tokens.brandX.ts ← Example teal brand
pages/
TokensDebug.tsx ← Debug page showing all token values
App.tsx ← App root with TokensProviderTo switch brands, edit template/src/design-tokens/tokens.ts:
// Default theme
export { defaultThemeTokens as tokens } from './tokens.default';
// Switch to Brand X
// export { brandXTokens as tokens } from './tokens.brandX';Development
# Install dependencies
npm install
# Start Storybook
npm run storybook
# Type-check
npm run lint
# Build
npm run buildBuild Output
dist/
index.mjs ← ESM
index.js ← CJS
index.d.ts ← TypeScript declarations
index.d.mts ← ESM TypeScript declarationsPeer Dependencies
react>= 18.0.0react-dom>= 18.0.0
License
ISC
