@djangocfg/ui-core
v2.1.237
Published
Pure React UI component library without Next.js dependencies - for Electron, Vite, CRA apps
Downloads
7,667
Maintainers
Readme

@djangocfg/ui-core
Pure React UI library with 65+ components built on Radix UI + Tailwind CSS v4.
No Next.js dependencies — works with Electron, Vite, CRA, and any React environment.
Part of DjangoCFG — modern Django framework for production-ready SaaS applications.
Install
pnpm add @djangocfg/ui-coreWhy ui-core?
| Package | Use Case |
|---------|----------|
| @djangocfg/ui-core | Electron, Vite, CRA, any React app |
| @djangocfg/ui-tools | Heavy tools with lazy loading |
| @djangocfg/ui-nextjs | Next.js apps (extends ui-core) |
Components (60+)
Forms (18)
Label Button ButtonLink Input Checkbox RadioGroup Select Textarea Switch Slider Combobox MultiSelect CountrySelect LanguageSelect InputOTP PhoneInput Form Field
Layout (8)
Card Separator Skeleton AspectRatio Sticky ScrollArea Resizable Section
Overlay (7)
Dialog AlertDialog Sheet Drawer Popover HoverCard Tooltip
Feedback (5)
Toaster Alert Progress Badge Avatar
Data (8)
Table Tabs Accordion Collapsible Toggle ToggleGroup Calendar Carousel
Interactive (3)
Command ContextMenu Chart
Specialized (13)
ButtonGroup Empty Spinner Preloader Kbd TokenIcon InputGroup Item ImageWithFallback OgImage CopyButton CopyField StaticPagination
Hooks (16)
| Hook | Description |
|------|-------------|
| useMediaQuery(query) | Raw media query — pass any CSS query string. Exports BREAKPOINTS constants (Tailwind v4 defaults) |
| useIsPhone() | < 640px — phones only |
| useIsMobile() | < 768px — phones + small tablets |
| useIsTabletOrBelow() | < 1024px — phones + tablets |
| useCopy | Copy to clipboard |
| useCountdown | Countdown timer |
| useDebounce | Debounce values |
| useDebouncedCallback | Debounced callbacks |
| useImageLoader | Image loading state |
| useToast / toast | Toast notifications (Sonner) |
| useEventListener | Event bus |
| useDebugTools | Debug utilities |
| useHotkey | Keyboard shortcuts (react-hotkeys-hook) |
| useBrowserDetect | Browser detection (Chrome, Safari, in-app browsers, etc.) |
| useDeviceDetect | Device detection (mobile, tablet, desktop, OS, etc.) |
| useResolvedTheme | Current resolved theme (light/dark/system) |
import { useMediaQuery, useIsPhone, useIsMobile, BREAKPOINTS } from '@djangocfg/ui-core/hooks'
// semantic
const isPhone = useIsPhone() // < 640px
const isMobile = useIsMobile() // < 768px
// custom with constants
const isNarrow = useMediaQuery(`(max-width: ${BREAKPOINTS.sm - 1}px)`)
const isDark = useMediaQuery('(prefers-color-scheme: dark)')Theme Palette Hooks
Hooks for accessing theme colors from CSS variables (useful for Canvas, SVG, charts, diagrams, etc.):
| Hook / Util | Description |
|-------------|-------------|
| useThemePalette() | Full hex color palette from CSS variables |
| useThemeColor(var, opacity?) | Single color by CSS var name — lighter alternative |
| useStylePresets() | Pre-built { fill, stroke, color } configs for diagrams |
| useBoxColors() | Semi-transparent RGBA colors for boxes/containers |
| alpha(hex, opacity) | Convert hex color to rgba() string |
import {
useThemePalette,
useThemeColor,
useStylePresets,
useBoxColors,
alpha,
} from '@djangocfg/ui-core/styles/palette';
function MyCanvas() {
const palette = useThemePalette();
// Use in Canvas / inline styles
ctx.fillStyle = palette.primary; // '#a855f7' (theme-aware)
ctx.fillStyle = alpha(palette.primary, 0.3); // 'rgba(168, 85, 247, 0.3)'
}
function MyWaveform() {
// Lighter: only subscribes to 'primary', not the entire palette
const primary = useThemeColor('primary'); // '#a855f7'
const primaryFaded = useThemeColor('primary', 0.3); // 'rgba(168, 85, 247, 0.3)'
const errorBackground = useThemeColor('destructive', 0.1);
}
function MyChart() {
const presets = useStylePresets();
// presets.primary = { fill: '#a855f7', stroke: '#a855f7', color: '#fff' }
// presets.success = { fill: '#22c55e', stroke: '#22c55e', color: '#fff' }
// presets.danger = { fill: '#ef4444', stroke: '#ef4444', color: '#fff' }
// presets.warning = { fill: '#f59e0b', stroke: '#f59e0b', color: '#fff' }
// presets.info = { fill: '#3b82f6', stroke: '#3b82f6', color: '#fff' }
const boxes = useBoxColors();
// boxes.primary = 'rgba(168, 85, 247, 0.15)' (0.3 in dark mode)
// boxes.success = 'rgba(34, 197, 94, 0.15)'
// etc.
return <Chart colors={[presets.success.fill, presets.warning.fill]} />;
}Color Utilities (HSL conversion)
import { hslToHex, hslToRgbString, hslToRgba } from '@djangocfg/ui-core/styles/palette';
hslToHex('217 91% 60%'); // '#3b82f6'
hslToRgbString('217 91% 60%'); // 'rgb(59, 130, 246)'
hslToRgba('217 91% 60%', 0.5); // 'rgba(59, 130, 246, 0.5)'Dialog Service
Universal dialog service to replace native window.alert, window.confirm, window.prompt with beautiful shadcn dialogs.
import { DialogProvider, useDialog, dialog } from '@djangocfg/ui-core/lib/dialog-service';
// Wrap your app with DialogProvider
function App() {
return (
<DialogProvider>
<YourApp />
</DialogProvider>
);
}
// Use via React hook
function Component() {
const { alert, confirm, prompt } = useDialog();
const handleDelete = async () => {
const confirmed = await confirm({
title: 'Delete item?',
message: 'This action cannot be undone.',
variant: 'destructive',
});
if (confirmed) {
// Delete...
}
};
}
// Or use globally from anywhere (vanilla JS, libraries, etc.)
dialog.alert({ message: 'Hello!' });
const ok = await dialog.confirm({ message: 'Are you sure?' });
const name = await dialog.prompt({ message: 'Enter your name:' });Usage
import { Button, Card, Input } from '@djangocfg/ui-core';
import { toast } from '@djangocfg/ui-core/hooks';
function Example() {
return (
<Card>
<Input placeholder="Email" />
<Button onClick={() => toast.success('Saved!')}>
Submit
</Button>
</Card>
);
}Electron Usage
// In Electron renderer process
import { Button, Dialog, useMediaQuery } from '@djangocfg/ui-core';
import '@djangocfg/ui-core/styles/globals';
function App() {
const isMobile = useMediaQuery('(max-width: 768px)');
return (
<Dialog>
<Button>Open Dialog</Button>
</Dialog>
);
}Styling (Next.js / Tailwind v4)
In your app's globals.css, import the package styles and add @source directives for every workspace package that ships Tailwind classes. Tailwind v4 does not scan node_modules automatically.
/* globals.css */
@import "@djangocfg/ui-nextjs/styles"; /* ui-core + ui-nextjs tokens & theme */
@import "@djangocfg/layouts/styles"; /* layout tokens */
@import "@djangocfg/ui-tools/styles"; /* heavy tool components */
@import "@djangocfg/debuger/styles"; /* debug panel (if used) */
@import "tailwindcss";Each package that ships Tailwind classes exposes a ./styles entry containing a single @source directive — no manual path configuration needed.
For non-Next.js (Electron, Vite):
import '@djangocfg/ui-core/styles/globals';Exports
| Path | Content |
|------|---------|
| @djangocfg/ui-core | All components & hooks |
| @djangocfg/ui-core/components | Components only |
| @djangocfg/ui-core/hooks | Hooks only |
| @djangocfg/ui-core/lib | Utilities (cn, etc.) |
| @djangocfg/ui-core/lib/dialog-service | Dialog service |
| @djangocfg/ui-core/utils | Runtime utilities (emitRuntimeError) |
| @djangocfg/ui-core/styles | CSS |
| @djangocfg/ui-core/styles/palette | Theme palette hooks & utilities |
Runtime Error Emitter
Emit runtime errors as events (caught by ErrorTrackingProvider in layouts):
import { emitRuntimeError } from '@djangocfg/ui-core/utils';
try {
doSomething();
} catch (error) {
emitRuntimeError('MyComponent', 'Operation failed', error, { extra: 'context' });
}What's NOT included (use ui-nextjs)
These features require Next.js or browser storage APIs:
Sidebar— uses next/linkBreadcrumb,BreadcrumbNavigation— uses next/linkNavigationMenu,Menubar— uses next/linkPagination,SSRPagination— uses next/linkDropdownMenu— uses next/linkDownloadButton— uses localStorageuseTheme— uses next-themesuseQueryParams,useCfgRouter— uses next/router
Requirements
- React >= 18 or >= 19
- Tailwind CSS >= 4
