pixelize-design-library
v3.3.1
Published
React component library for Pixelize apps: themeable Chakra-based components, design tokens and light/dark brand theming.
Readme
Pixelize Design Library
A comprehensive React component library built with TypeScript, providing a rich set of UI components for modern web applications.
Building with this library (including via an AI assistant)? Read COMPONENT-GOTCHAS.md first — it documents known silent-failure traps and which near-duplicate component to pick for what. It ships with this package, so it's available at
node_modules/pixelize-design-library/COMPONENT-GOTCHAS.mdtoo. Building a whole screen? DESIGN-GUIDE.md (also shipped) covers page anatomy, spacing, type, color roles and the four page states.
Features
- 🎨 Modern Design System - Consistent and beautiful components
- 📱 Responsive - Mobile-first design approach
- ♿ Accessible - Built with accessibility in mind
- 🔧 TypeScript - Full TypeScript support
- 🎯 Customizable - Easy theming and customization
- 📦 Tree-shakable - Import only what you need
Prerequisites
Before you begin, ensure you have the following installed:
- Node.js (v18 or higher)
- npm (v7 or higher) or yarn
- React and React DOM
^18.3.1
Installation
Install the library, then its peer dependencies:
npm install pixelize-design-librarynpm install @chakra-ui/react@^2.8.2 @emotion/react@^11.11.4 @emotion/styled@^11.11.5 framer-motion@^10.18.0react and react-dom are peers pinned to ^18.3.1. React 19 is not supported — the pin
tracks Chakra 2.8.
Versioning
Everything ships on the latest dist-tag. Stable 3.x takes a caret range:
"pixelize-design-library": "^3.0.0"There are no prereleases from 3.0.0 onward. The old 2.4.2-beta.N line was folded into 3.0.0; if you are
still pinned to one, change the pin to 3.0.0.
What changed in each release, and what breaks in 3.0.0: CHANGELOG.md.
Quick Start
import React from 'react';
import { Button, Card, TextInput } from 'pixelize-design-library';
function App() {
return (
<div>
<Card>
<TextInput placeholder="Enter your name" />
<Button variant="solid" colorScheme="primary">Submit</Button>
</Card>
</div>
);
}
export default App;Building screens? Use the library component for every control, never the browser's or Chakra's —
DESIGN-GUIDE.md §5a maps each native
element to its component and props (e.g. Select always takes native={false}).
Theming and filled surfaces
Nine brand presets with light/dark palettes. Wrap your app in PixelizeThemeProvider and read tokens
via useCustomTheme().
Do not pair a scale's [500] swatch with colors.white or onPrimary for custom filled UI —
white often fails WCAG on [500] and ink falls back to black (e.g. black text on red badges). Use
library components (Button, Tag, Badge) or:
import { resolveFilledSurface, useCustomTheme } from "pixelize-design-library";
const { colors } = useCustomTheme();
const solid = resolveFilledSurface(colors.red, colors);
// solid.fill, solid.color, solid.hoverFill, solid.hoverColor, …Full rules for app developers and AI assistants: src/Theme/THEME-CONTRACT.md
(§ Filled surfaces in consumer apps). After upgrading, rebuild the library (npm run build) and run
npm run pixelize in consumer frontends.
Components
Layout & Navigation
- Accordion - Collapsible content sections
- Breadcrumbs - Navigation breadcrumb trail
- Card - Container component for content
- Modal - Overlay dialog component
- NavigationBar - Main navigation component
- SideBar - Side navigation panel
Form Controls
- Button - Interactive button component
- ButtonGroupIcon - Icon-based button group
- Checkbox - Checkbox input control
- DatePicker - Date selection component
- Dropdown - Action menu (a menu button, not a value picker)
- MultiSelect - Typed email-chip input (no options list)
- NumberInput - Numeric input field
- PinInput - PIN/OTP input component
- RadioButton - Radio button input
- RadioButtonGroup - Group of radio buttons
- RangeSlider - Single or dual-thumb slider with tick marks
- Search - Search input component
- SearchSelect - Searchable select dropdown
- Select - Native or themed popup picker, single or multi, optionally searchable
- ToggleSwitch - On/off switch (
Switchis a deprecated two-option pill) - TextInput - Text input field
- InputTextArea - Multi-line text input
- NoteTextArea - Textarea with a title and file attach (not rich text; use
Editor)
Data Display
- Table - Data table component
- MediaViewer - Full-screen viewer for images, video, audio, PDF, Office, text and archives
- Timeline - Timeline visualization
- Skeletons - Loading skeleton components
- ProgressBar - Progress indicator
Charts & Visualization
- ApexBarChart - Bar chart component
- ApexPieChart - Pie chart component
Feedback & Status
- AlertDialog - Confirm dialog for destructive actions
- ConfirmDialog - Cancel/Confirm prompt, with optional typed confirmation
- NotificationBell - Badge/bell button
- NotificationPanel / NotificationList / NotificationItem - the tray, its body and one row
- Loading - Blocking loading overlay (
Backdropfor a lighter scrim) - Spinner - Themed inline spinner
- Toaster - Toast notification system
- useToaster - Hook for toast management
- ToolTip - Tooltip component
User & Profile
- Avatar / AvatarGroup - Fill derived from
name, so it follows brand and dark mode - ProfileCard - User profile card
- ProfilePhotoViewer - Profile photo viewer
- VerifyEmailOtp - Email verification component
Editor
- Editor - Rich text editor component
The lists above are the common components. Every export, including the helpers, hooks and tokens, is in the Exports index.
Usage Examples
Basic Button Usage
import { Button } from 'pixelize-design-library';
function MyComponent() {
return (
<div>
<Button variant="solid" colorScheme="primary">Primary Button</Button>
<Button variant="outline" colorScheme="gray">Secondary Button</Button>
</div>
);
}Form with Validation
import { useState } from 'react';
import { TextInput, Button, Card } from 'pixelize-design-library';
function LoginForm() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
return (
<Card>
<TextInput
label="Email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
<TextInput
label="Password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
<Button variant="solid" colorScheme="primary" type="submit">
Login
</Button>
</Card>
);
}Data Table
import { Table } from 'pixelize-design-library';
const columns = [
{ id: 'name', label: 'Name' },
{ id: 'email', label: 'Email' },
{ id: 'role', label: 'Role' }
];
// every row needs a unique id
const data = [
{ id: 1, name: 'John Doe', email: '[email protected]', role: 'Admin' },
{ id: 2, name: 'Jane Smith', email: '[email protected]', role: 'User' }
];
function DataTable() {
return (
<Table
columns={columns}
data={data}
paginationMode="client"
isGlobalSearch
/>
);
}Theming
The library ships 9 brand themes (lavender, meadow, radiant, skyline, slate,
emerald, rosewood, storefront, zinc), each with a light and a dark palette.
Existing apps (unchanged)
withTheme is the original default export and still renders light only. Upgrading the package
changes nothing visually:
import withTheme, { ThemesList } from 'pixelize-design-library';
export default withTheme(App, ThemesList.lavender);Opting into light / dark / system
Wrap the app in PixelizeThemeProvider instead. It defaults to system (follows the OS) and
persists the user's choice to localStorage.
import { PixelizeThemeProvider, ThemeSwitcher } from 'pixelize-design-library';
function Root() {
return (
<PixelizeThemeProvider brand="lavender" defaultMode="system">
<App />
</PixelizeThemeProvider>
);
}
// Drop the switcher anywhere inside the provider:
<ThemeSwitcher /> // icon toggle
<ThemeSwitcher variant="segmented" /> // Light / System / Dark
<ThemeSwitcher variant="menu" showBrandPicker /> // + brand picker| PixelizeThemeProvider prop | Default | Meaning |
| ---------------------------- | ------- | ------- |
| brand | "lavender" | Which brand theme to use |
| defaultMode | "system" | "light" | "dark" | "system" |
| storageKey | "pixelize-theme" | localStorage key |
| disablePersistence | false | Don't read/write localStorage |
| onBrandChange / onModeChange | — | Fire on user-driven changes only |
| themeOverrides | — | Chakra theme object merged over the brand theme |
| reducedMotion | "components" | "global" applies one reduced-motion rule to the whole document |
Reading or changing the theme in code
import { useThemeMode, useCustomTheme } from 'pixelize-design-library';
const { mode, resolvedMode, setMode, toggle, brand, setBrand } = useThemeMode();
const theme = useCustomTheme(); // returns the palette for the ACTIVE color modeuseCustomTheme() returns the dark palette automatically in dark mode, so components that read
their colors from it are dark-aware with no extra work.
Building components
Read colors from the theme — never hardcode a hex, or the component will be stuck in light mode:
const theme = useCustomTheme();
<Box bg={theme.colors.background[50]} color={theme.colors.text[900]} /> // ✅ adapts
<Box bg="#ffffff" color="#26213c" /> // ❌ breaks in darkcolors.white is a foreground token (the label on a filled button) and stays white in dark
mode. For a white surface, use colors.background[50].
Design tokens (shared with the mobile library)
lightPalettes, darkPalettes, palettes, themeNames, and buildDarkPalette are exported for
apps that build custom themes. The token source (src/Theme/tokens/) is pure TypeScript with no
Chakra, React, or CSS imports, so it is portable to React Native.
import { lightPalettes, buildDarkPalette } from 'pixelize-design-library';
const myDark = buildDarkPalette(lightPalettes.emerald);TypeScript Support
All components are built with TypeScript and include full type definitions:
import { Button, ButtonProps } from 'pixelize-design-library';
interface CustomButtonProps extends ButtonProps {
customProp?: string;
}
function CustomButton({ customProp, ...props }: CustomButtonProps) {
return <Button {...props} />;
}Bundle size and tree-shaking
The package ships both CommonJS (main) and ES modules (module). Bundlers pick the ESM
build and tree-shake it, so you only pay for what you import:
import { Button } from 'pixelize-design-library';That import produces roughly 113 KB — it contains no chart, editor, drag-and-drop, virtual-list or date code, even though the package depends on all of them.
To keep it that way:
- Import from the package root. The root barrel is tree-shakeable; there is no size penalty for it, and it is the only path covered by semver.
- Do not import from
dist/for values. Deep imports still work (and are used for types), but they bypass the ESM build and pull in the CommonJS copy. - Do not disable
sideEffectshandling in your bundler config.
Heavy components load on demand
Editor wraps Jodit, which is by far the largest dependency. It is loaded lazily, when the
component first renders, rather than when the package is imported. An app that uses Editor
ships about 96 KB up front and fetches the ~1.5 MB editor chunk on demand. No extra setup
is required — Editor renders its own Suspense boundary.
Fonts
The theme self-hosts Inter Variable. The stylesheet is split by unicode-range, so a
Latin-script page downloads a single 47 KB font file; Cyrillic, Greek and Vietnamese
subsets are only fetched if the page actually renders those scripts.
Server-side rendering
Components are browser-targeted and the theme imports a CSS file, so the package must be transpiled by your bundler rather than imported by bare Node. In Next.js:
// next.config.js
module.exports = { transpilePackages: ['pixelize-design-library'] };Exports index
Every value the package root exports, so an export is never invisible to a developer or an LLM that
only has this package. For how to use a component see DESIGN-GUIDE.md and
COMPONENT-GOTCHAS.md; props are documented in the *Props types. This
block is generated: after adding or removing an export run
UPDATE_README_EXPORTS=1 npx jest src/readmeExportsIndex.test.ts --coverage=false.
Components and primitives (278)
Accordian, Accordion, AddressCard, AddressCardGroup, Alert, AlertDescription, AlertDialog, AlertIcon, AlertTitle, ApexAreaChart, ApexBarChart, ApexLineChart, ApexPieChart, ApexPolarChart, ApexRadialChart, AppSwitcher, AppearanceSettings, AssistantApprovalCard, AssistantComposer, AssistantContextBar, AssistantHistoryList, AssistantLauncher, AssistantMarkdown, AssistantMessage, AssistantPanel, AssistantProposalCard, AssistantSources, AssistantStatusBanner, AssistantSuggestions, AssistantThread, AssistantToolSteps, AssistantTypingIndicator, AssistantWelcome, AudioRecorder, Avatar, AvatarGroup, Backdrop, Badge, BagBar, Box, Breadcrumbs, BulkSelectionBar, Button, ButtonGroupIcon, CalendarGrid, Card, CartItem, Center, ChakraProvider, Checkbox, ChoiceCard, ChoiceCardGroup, CircularProgress, Collapse, ConfirmDialog, ContactForm, Container, CopyButton, CouponField, CustomModulesTable, DatePicker, DescriptionList, DetailSections, Divider, Drawer, DrawerBody, DrawerFooter, DrawerHeader, Dropdown, Editor, EmptyState, ErrorState, FeedbackForm, FieldMessage, FieldSelectModal, FilePreview, FilePreviewTrigger, FileUpload, FileUploader, FilterBar, FilterSidebar, FilteredEmptyState, Flex, FormControl, FormDrawer, FormErrorMessage, FormField, FormHelperText, FormLabel, FormWrapper, Grid, GridItem, Header, HeaderActions, Heading, Hide, Icon, IconButton, Image, InputSwitch, InputTextArea, KanbanActions, KanbanBoard, Kbd, KbdShortcut, LauncherSearchEngine, LauncherTrigger, LazyWrapper, LimitReachedModal, Link, List, ListIcon, ListItem, Loading, MediaAudioPlayer, MediaDocumentStage, MediaGallery, MediaImageViewer, MediaLightbox, MediaScrubber, MediaStatusPanel, MediaVideoPlayer, MediaViewer, Menu, MenuButton, MenuDivider, MenuGroup, MenuItem, MenuItemOption, MenuList, MenuOptionGroup, Modal, ModalBody, ModalFooter, ModalHeader, MoreItems, MultiSelect, NavLauncher, NavigationBar, NewTabLink, NoteTextArea, Notification, NotificationBell, NotificationCenter, NotificationCenterProvider, NotificationDetail, NotificationInbox, NotificationItem, NotificationList, NotificationPanel, NotificationPreferences, NotificationRow, NumberInput, OffersList, OptionChip, OrderStatusTimeline, OrderSummary, OrderedList, OrgSwitcher, OrganizationDetails, OverflowToolTip, PageHeader, Pagination, PaymentCard, PaymentOption, PaymentOptionGroup, PdfViewer, PersonChip, PhoneNumberInput, PinInput, PinToggle, PincodeChecker, PixelizeThemeProvider, PlanBadge, PlanPill, Popover, PopoverArrow, PopoverBody, PopoverCloseButton, PopoverContent, PopoverFooter, PopoverHeader, PopoverTrigger, Portal, PriceBlock, ProductBadges, ProductCard, ProductCardGrid, ProductCardSkeleton, ProductDetails, ProfileCard, ProfileCardBody, ProfileCardFooter, ProfileCardHeader, ProfilePhotoViewer, ProgressBar, QuantityStepper, QueryStateBoundary, QuickAddSheet, RadioButton, RadioButtonGroup, RangeSlider, Rating, Reorder, ReviewList, ReviewSummary, RolesPermission, SaveBar, ScrollToTop, ScrollbarBox, Search, SearchSelect, SectionRail, SegmentedControl, Select, SelectSearch, SelectV2, SettingRow, SettingsSection, Show, SideBar, SignInActivityTable, SimpleGrid, Skeletons, SkipLink, Slider, Spacer, SpecTable, Spinner, Stack, StageItem, StageProgress, StatCard, StatusTag, StickyBuyBar, StockStatus, Switch, Tab, TabList, TabPanel, TabPanels, Table, TableContainer, TableRoot, TableToggle, Tabs, Tag, TagInput, Tbody, Td, Text, TextInput, Tfoot, Th, Thead, ThemeSwitcher, ThemesList, TimePicker, Timeline, Toaster, ToggleSwitch, ToolTip, Tr, TrustBadges, UnorderedList, UpgradeButton, UserDetails, VariantSelector, VerifyEmailOtp, VisuallyHidden, WishlistToggle, Wizard, WizardDialog, WorkspaceTray, WorkspaceTrayPreview, WorkspaceWindow, Wrap, WrapItem
Hooks (19)
useAnchoredPanelHeight, useAppSwitcherShortcut, useBreakpointValue, useChartTheme, useCustomTheme, useDebouncedCallback, useDebouncedValue, useDisclosure, useFieldIds, useFileViewer, useFontSizeSync, useIsTruncated, useMediaQuery, useNotificationCenter, usePrefersReducedMotion, useSidebarPrefs, useThemeMode, useToaster, useToken
Constants (46)
AA_NON_TEXT, AA_NORMAL_TEXT, ACCENT_GRADIENT, AVATAR_SEEDS, BORDER_WIDTHS, CALENDAR_DAY_CLASS, CATEGORICAL_SERIES, CONTROL_SIZES, CONTROL_SIZE_NAMES, DARK_CANVAS_LUMINANCE, DAY_STATE_KEYS, DEFAULT_CONTROL_SIZE, DEFAULT_DATE_FALLBACK, DEFAULT_FONT_SIZE, DEFAULT_NOTIFICATION_LOCALE, DISABLED_OPACITY, EMAIL_REGEX, FOCUS_HALO_WIDTH, FOCUS_RING_WIDTH, FOCUS_VISIBLE_OVER_STATE, FONT_SIZE_OPTIONS, LOW_STOCK_THRESHOLD, MAX_ZOOM, MIN_ZOOM, MOTION_BEZIER, MOTION_EASE, MOTION_EASE_IN, MOTION_EASE_OUT, MOTION_KEEP_CLASS, MOTION_LOOP_MS, MOTION_MS, MOTION_PRESS_SCALE, NUMERIC_TEXT, OVERLAY_BLUR, PIXELIZE_SUITE, PLAYBACK_SPEEDS, RADIUS_ROLE, RAISED_OVERLAY, REDUCED_MOTION_QUERY, SCRIM_OPACITY, SCROLLBAR_WIDTH, SEEK_STEP_SECONDS, STATUS_INK, TEXT_STYLES, TONES, ZOOM_STEP
Helpers and tokens (189)
HStack, VStack, accentTextOnCanvas, accentTextOnPlanes, appInitials, avatarFillFor, avatarScaleKeyFor, bandOn, brandThemes, buildDarkPalette, buildFileItems, buildFocusRing, buildMediaItems, buildSuiteApps, buildSurfaceRaised, cardRule, chartAxisLabelColor, chartInk, chartMode, chipBorder, chipFill, chipHtml, chipify, clearChunkReloadGuard, compositeOver, contrastRatio, controlSizeStyles, countMedia, createAccountHandoff, createEnumLabelResolver, darkPalettes, darkerFillRung, debounce, default, defaultMediaAudioPlayerLabels, defaultMediaDocumentStageLabels, defaultMediaGalleryLabels, defaultMediaImageViewerLabels, defaultMediaLightboxLabels, defaultMediaVideoPlayerLabels, defaultMediaViewerLabels, defaultNotificationLabels, defaultPaginationLabels, defaultValidationMessages, describeDayStates, discountAmount, discountPercent, downloadBlob, extendTheme, extractTokens, fieldControlStyles, fieldLabelStyles, fieldMessageStyles, fieldSurfaces, fieldToken, fileKind, filterApps, findVariant, firstAvailableSelection, firstInvalidStep, flattenScreens, focusRingShadow, focusVisibleRing, focusVisibleStyles, formatCount, formatDate, formatDateRange, formatDateTime, formatPlanElapsed, formatPlanExpiry, formatPlanRemaining, formatPrice, formatRelativeTime, formatShortcut, getApiErrorMessage, getApiErrorStatus, getCategoricalSeriesColors, getDefaultSeriesColors, globalScrollbarStyles, gradientCss, groupConsecutive, hexToHsl, hexToRgb, hexToRgba, highlightSegments, hslToHex, hslToRgb, humanize, initialsFor, inkSafeGradient, inkSafeGradientToken, installPreloadErrorReload, isAllowedReturnUrl, isChunkLoadError, isControlSize, isDarkCanvas, isDayStateKey, isFontSize, isNotificationActionError, isOptionAvailable, isTone, labelOnFill, labelOnSeries, lazyWithRetry, liftToContrast, lightPalettes, listRowBackgrounds, matchesShortcut, meetsBodyText, mergeRefs, mix, motionTransition, notificationActionError, onFilled, onGradient, optionRowCursorSx, optionRowDescriptionInk, optionRowFill, optionRowInk, optionRowWeight, overlayScrim, overlayScrimStyles, palettes, pickAccentText, placeholderInk, placeholderInkOn, planPreview, priceRange, rafThrottle, raisedRule, recessOn, reducedMotionSx, relativeLuminance, remainingStock, resolveAvatarColorway, resolveAvatarFill, resolveDayStateVisual, resolveFilledSurface, resolveFontSize, resolveGradient, resolveMediaUrl, resolvePlanBadge, resolveReturnUrl, resolveSoftTone, resolveStatusTone, resolveSuiteApps, rgbToHex, rgbToHsl, ruleOn, safeFileName, scrollbarStyles, searchLauncher, searchLauncherSections, sectionizeByDay, selectionComplete, serializeChips, setRef, settleBetween, shadowsFor, solidFillRung, splitMonthsAndDays, statusGradient, stockState, themeNames, toCsv, toNotificationActionError, toWords, toneInk, toneScale, toneToColorScheme, toneToSemantic, tooltipSurface, transitionFor, unitPrice, unknownTokens, validateEmail, validateFile, validateFileSize, validateFileType, validatePassword, validatePositiveNumber, validateRequired, validateVideoFile, validateVideoFileType, validateYoutubeUrl, withFocusRing, withLightness, withOutlineRung, wizardTransition
Demo app
npm start runs a local component explorer on http://localhost:5173 — every exported
component on its own page, with live variants, an interactive playground for editing props,
and a generated props reference. The Page examples section shows full screens (dashboard,
records list, record detail, settings, pipeline, inbox, app launcher, wizard, template editor,
storefront) built only from library exports, each with its loading, empty and error states.
npm install
npm startThe demo lives in src/Pages/ and is excluded from the published package. See
GOTCHAS.md for the traps involved in keeping it that way.
Contributing
Read CLAUDE.md for the repo layout, component pattern and the checklist for
adding a component, and GOTCHAS.md before touching the theme provider, the
build config or package.json.
npm install
npm start # demo app on :5173
npm test # Jest — not vitest
npm run lint
npm run typecheckEvery component needs a demo page in src/Pages/ and Jest tests next to the component.
License
Not yet declared. The license field in package.json is unset and there is no LICENSE
file in the repo — both need the owning entity's decision before the package is published
outside the organisation.
