@scalably/ui
v0.9.8
Published
Scalably Design System - Shared UI Components
Downloads
1,970
Maintainers
Readme
Scalably UI Component Library
A modern, accessible, and fully isolated React component library built with TypeScript and Tailwind CSS. Designed to work seamlessly across multiple projects without style conflicts.
🚀 Features
- Style Isolation: All components use prefixed Tailwind classes (
sui-*) to prevent conflicts - TypeScript First: Full type safety with comprehensive prop interfaces
- Accessible: Built with accessibility best practices and WCAG compliance
- Modern: Uses latest React patterns and modern build tools (tsup, Vite, Storybook)
- Rich Text Editing: TipTap-based editor with character counting, media embeds, and formatting toolbar
- Customizable: Flexible variant system with class-variance-authority
- Comprehensive: 20+ production-ready components with full documentation
- Production Ready: Complete build pipeline with CommonJS and ES modules
- Icons & Assets: First-class icon set, avatar placeholders, and logo assets
- Utilities & Helpers: Shared date helpers, form helpers, and utility functions (
cn,debounce,throttle,scopeClass)
📦 Installation
npm install @scalably/ui🎨 Usage
1. Use Components (Styles Auto-Injected)
The ScalablyUIProvider automatically injects styles into document.head, so you don't need to manually import CSS. This ensures styles work correctly in portals (modals, tooltips, etc.). No wrapper or scope class is required—just wrap your app once.
import { ScalablyUIProvider, Form, FormField, Input, Button, ToastContainer, Toast } from "@scalably/ui";
export default function App() {
return (
<ScalablyUIProvider>
<main>
<Form onSubmit={(e) => e.preventDefault()}>
<FormField label="Email" htmlFor="email">
<Input id="email" type="email" placeholder="Enter your email" />
</FormField>
<Button className="sui-mt-4" type="submit">Submit</Button>
</Form>
{/* Toasts */}
<ToastContainer />
<Toast status="success" title="Welcome" description="You're all set." />
</main>
</ScalablyUIProvider>
);
}2. Optional: Manual CSS Import
If you prefer to import CSS manually (e.g., for better control or SSR optimization), you can disable automatic injection:
// In your main.tsx, App.tsx, or index.tsx
import "@scalably/ui/styles";
import { ScalablyUIProvider } from "@scalably/ui";
export default function App() {
return (
<ScalablyUIProvider injectStyles={false}>
{/* your app */}
</ScalablyUIProvider>
);
}3. Portal Support
Styles automatically work in portaled components (modals, tooltips, popovers, etc.) because:
- Styles are injected globally into
document.head - CSS variables propagate to all elements
- No parent selector dependencies
// Tooltips, modals, and other portaled components work automatically
<Tooltip content="This works in portals!" portal>
<Button>Hover me</Button>
</Tooltip>Note: Toasts in this library are intentionally declarative. Render a Toast inside a ToastContainer when you want it visible (e.g., based on component state). This avoids hidden globals and keeps UI state predictable. If you prefer an imperative API, you can wrap your own tiny helper around local state to toggle a Toast component.
4. React import guidance
If you reference the React namespace (e.g., React.useState, React.forwardRef, React.SVGProps) add an explicit import to avoid UMD global errors:
import * as React from "react";Alternatively, import only what you use with the automatic JSX runtime:
import { useState, forwardRef } from "react";
import type { SVGProps } from "react";Helper Functions
- Date helpers:
addMonths,clampDate,daysGrid,endOfMonth,formatDateLocalized,isSameDay,monthsForLocale,startOfMonth,toDateKey,weekdaysForLocale - Form helpers:
fieldErrorToProps,zodErrorsToSummaryandtype FieldErrorLike - Utilities:
cn(Tailwind-aware className helper),debounce,throttle,scopeClassfor safely buildingsui-*class strings
Example Usage
import {
AuthPrompt,
BackToTop,
Button,
CheckboxGroup,
DatePicker,
FileUpload,
Input,
Pagination,
RichTextEditor,
Select,
Toast,
ToastContainer,
ViewToggle,
} from '@scalably/ui';
// Button with variants
<Button variant="destructive">Delete</Button>;
<Button variant="outline">Cancel</Button>;
<Button loading>Loading...</Button>;
// Input with validation
<Input
label="Email Address"
type="email"
placeholder="Enter your email"
error="Please enter a valid email"
/>;
// Date picker
<DatePicker
mode="single"
placeholder="Select a date"
onChange={(date) => console.log(date)}
/>;
// Toast notifications (declarative)
<ToastContainer>
<Toast
status="success"
title="Success!"
description="Your changes have been saved."
/>
</ToastContainer>;
// Rich text editor
<RichTextEditor
value="<p>Start writing...</p>"
onChange={(value) => console.log(value)}
maxCharacters={5000}
/>;
// Marketing-style auth prompt card
<AuthPrompt
title="Welcome back"
description="Log in to manage your campaigns."
primaryActionLabel="Log in"
onPrimaryAction={() => console.log('login')}
/>;
// Toggle between list and grid views
<ViewToggle view="list" onViewChange={(v) => console.log(v)} />;
// Scroll-to-top helper
<BackToTop />;🧩 Components & APIs Overview
This library exposes a set of composable, production-ready primitives. The full list of exports is available in src/index.ts, but the main groups are:
- Form primitives:
Form,FormField,FormErrorSummary,Input,SearchInput,QuantityInput,CheckBox,CheckBoxGroup,Radio,RadioGroup,Select,Switch,FileUpload,DateInput,DatePicker,TimePicker - Feedback & status:
StatusBadge,Toast,ToastContainer,Skeleton,SkeletonText,Countdown - Layout & navigation:
Tabs,TabsList,TabsTrigger,TabsContent,Pagination,BackToTop,ViewToggle,Divider - Content & rich text:
RichTextEditor,RichTextViewer,Tooltip,AuthPrompt,LoadingScreen,WelcomeBackground - Media & brand:
AvatarPlaceholder,Logo,logoAssets,defaultAssets,welcomeAssets(all inline React SVGs—no static paths required) - Icons: All icons from
@/iconsand@/icons/companyare re-exported, e.g.SearchIcon,CalendarIcon,SuccessIcon,ErrorIcon,DiscordIcon,FacebookIcon,XIcon,YoutubeIcon, and more.
🖼️ Assets
All library assets are inline React SVG components (welcome background, logos, avatar placeholders). You can use them directly via the exported asset maps (welcomeAssets, logoAssets, defaultAssets) or override props (size, className, aria-label). If you prefer external URLs (e.g., CDN), pass your own backgroundImage, ellipsesData, or linesSrc to WelcomeBackground.
🎨 Styling
Style Isolation
All components use prefixed Tailwind classes (sui-*) to ensure complete style isolation:
// ✅ Correct - components are properly isolated
<Button>Isolated Button</Button>
// ✅ Your global styles won't break the components
<div className="p-4 bg-red-500">
<Button>Isolated Button</Button>
</div>Custom Styling
You can still customize components using the className prop:
<Button className="sui-w-full sui-mt-4">Full Width Button</Button>
<Card className="sui-max-w-md sui-mx-auto">Centered Card</Card>🛠 Development
Prerequisites
- Node.js 18+
- npm or pnpm
Setup
# Clone the repository
git clone [email protected]:quangnle/scalably-components.git
cd scalably-components
# Install dependencies
npm install
# Start Storybook for development
npm run storybook
# Build the library
npm run build
# Run tests
npm testAvailable Scripts
npm run dev- Start development build with watch modenpm run build- Build the library for productionnpm run build:css- Build CSS styles separatelynpm run storybook- Start Storybook development servernpm run build-storybook- Build Storybook for productionnpm run lint- Run ESLintnpm run lint:fix- Run ESLint with auto-fixnpm run type-check- Run TypeScript type checkingnpm test- Run testsnpm run test:watch- Run tests in watch modenpm run test:ci- Run tests with coveragenpm run verify- Run verification scriptnpm run clean- Clean build artifacts
📚 Documentation
Visit our Storybook documentation for:
- Interactive component playground
- Comprehensive prop documentation
- Usage examples and best practices
- Design system guidelines
- Accessibility testing with axe-core
- Design tokens and theming
You can access the latest published Storybook at: https://scalably.com/dev/storybook.
🎨 Design System
Colors
- Primary:
#36499B– Main brand color for primary actions (sui-bg-primary,sui-text-primary) - Secondary:
#F2F6FC– Light background colors (sui-bg-secondary,sui-text-secondary) - Success:
#22BC4D– Positive actions and success states (sui-bg-success,sui-text-success) - Warning:
#FF7A00– Caution and in-progress states (sui-bg-warning,sui-text-warning) - Info:
#2772F0– Informational content (sui-bg-info,sui-text-info) - Error:
#EA3540– Destructive actions and errors (sui-bg-error,sui-text-error) - Inactive:
#777E90– Inactive or completed states (sui-text-inactive,sui-border-inactive) - Disabled:
#B2BBC7– Disabled elements (sui-text-disabled,sui-border-disabled)
Typography
- Font Family: Poppins (primary), Inter (fallback), system-ui
- Font Sizes: 12px, 14px, 16px, 20px, 24px with 150% line-height and -2% letter-spacing
- Font Weights: 400 (normal), 500 (medium), 600 (semibold), 700 (bold)
🔧 Configuration
Fonts
The library uses the Poppins font family (with Inter and system fonts as fallbacks) and loads Poppins via Google Fonts from within the bundled CSS. In most setups you do not need to add additional font imports, but if your build pipeline blocks remote @import rules, you can alternatively include Poppins yourself (e.g., via Google Fonts or @fontsource/poppins) to ensure consistent typography.
Tailwind Config
The library uses a custom Tailwind configuration with:
- Prefix:
sui-for all utility classes (provides style isolation) - Global Styles: Automatically injected via
ScalablyUIProvider - CSS Variables: Design tokens available globally for theming
- Custom Colors: Brand-specific color palette
- Custom Shadows: Soft, medium, and strong shadow variants
- Portal Support: Styles work in portaled components (modals, tooltips, etc.)
Build Configuration
- Bundler: tsup for fast, modern builds
- Formats: CommonJS and ES modules with proper exports
- TypeScript: Full type definitions included
- Tree Shaking: Optimized for minimal bundle size
- CSS: Separate CSS build with Tailwind compilation
- Source Maps: Generated for debugging
- Minification: Production builds are minified
📦 Publishing
Version Management
We use semantic versioning (semver):
- Major (1.0.0): Breaking changes
- Minor (0.1.0): New features, backward compatible
- Patch (0.0.1): Bug fixes, backward compatible
Publishing Process
# Build the library
npm run build
# Run tests
npm test
# Publish to registry
npm publishDevelopment Guidelines
- Follow TypeScript best practices
- Write comprehensive Storybook stories
- Ensure accessibility compliance
- Add tests for new components
- Update documentation
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🆘 Support
- Documentation: Storybook (run
npm run storybook) - Issues: GitHub Issues
- Discussions: GitHub Discussions
🧪 Testing
The library includes comprehensive testing setup:
- Unit Tests: Vitest with React Testing Library
- Accessibility: jest-axe for a11y testing
- Coverage: Built-in coverage reporting
- CI/CD: Automated testing pipeline
🔧 Dependencies
Peer Dependencies
- React 18+
- React DOM 18+
Key Dependencies
@floating-ui/react- Positioning for tooltips and popoversclass-variance-authority- Component variant managementdate-fns- Date manipulation utilitiesclsx- Conditional class namestailwind-merge- Tailwind class merging@tiptap/react&@tiptap/starter-kit- Rich text editor foundation@tiptap/extension-*- Rich text extensions (character count, image, alignment, placeholder, YouTube, etc.)
Built with ❤️ by the Scalably team
