Launch Week Day 5: Introducing Reachability for PHP.Learn More
Socket
Book a DemoSign in
Socket

@djangocfg/ui-core

Package Overview
Dependencies
Maintainers
1
Versions
273
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@djangocfg/ui-core

Pure React UI component library without Next.js dependencies - for Electron, Vite, CRA apps

latest
Source
npmnpm
Version
2.1.301
Version published
Weekly downloads
2.4K
64.89%
Maintainers
1
Weekly downloads
 
Created
Source

@djangocfg/ui-core

@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.

Live Demo & Props

Install

pnpm add @djangocfg/ui-core

Why ui-core?

PackageUse Case
@djangocfg/ui-coreElectron, Vite, CRA, any React app
@djangocfg/ui-toolsHeavy tools with lazy loading
@djangocfg/ui-nextjsNext.js apps (extends ui-core)

Components (65+)

Components are organized by category in components/. All exports are available from the root:

import { Button, Dialog, Table } from '@djangocfg/ui-core';

Forms (18)

Button ButtonLink ButtonGroup Input Textarea Checkbox RadioGroup Switch Slider Label Form Field InputOTP PhoneInput InputGroup DownloadButton OTPInput Textarea

Select (8)

Select Combobox MultiSelect MultiSelectPro MultiSelectProAsync CountrySelect LanguageSelect

Select Components — All select components now support icons and badges:

  • Select — Radix primitives with icon on trigger/item, badge on item
  • Combobox — Searchable single-select with icon + badge in trigger and dropdown
  • MultiSelectPro — Multi-select with colored badges, icons, animations

See components/select/README.md for full documentation.

Layout (8)

Card Separator Skeleton AspectRatio Sticky ScrollArea Resizable Section

Overlay (9)

Dialog AlertDialog Sheet Drawer Popover HoverCard Tooltip ResponsiveSheet SidePanel

Default TooltipContent styling uses semantic popover tokens (bg-popover, text-popover-foreground, border-border, shadow) — not primary — so hints read as neutral floating UI.

SidePanel — non-modal side drawer for inspector panels, playgrounds, filters. Slides in from the right (side="right", default) or left edge. Unlike Sheet/Drawer, it does NOT lock the rest of the page — surrounding UI stays clickable and focusable. Esc-to-close (toggleable) and swipe-to-close via vaul. Use when you want a slide-in surface that co-exists with the page below; for modal side surfaces, prefer Sheet.

<SidePanel open={open} onOpenChange={setOpen} side="right">
  <SidePanel.Content width="440px">
    <SidePanel.Header>
      <SidePanel.Title>Details</SidePanel.Title>
      <SidePanel.Close className="ml-auto" />
    </SidePanel.Header>
    <SidePanel.Body></SidePanel.Body>
    <SidePanel.Footer></SidePanel.Footer>
  </SidePanel.Content>
</SidePanel>

Drawer — modal vaul-based panel that slides in from any edge (top / right / bottom / left). Picks a size from a preset table or takes an explicit CSS length; both are applied via inline style so vaul's first-paint measurement matches the final layout (no inset miscalc).

<Drawer direction="right">
  <DrawerTrigger asChild><Button>Open</Button></DrawerTrigger>
  <DrawerContent direction="right" size="lg">
    <DrawerHeader>
      <DrawerTitle>Details</DrawerTitle>
    </DrawerHeader></DrawerContent>
</Drawer>

Size presets — sm md lg xl full. Maps to width for left/right, height for top/bottom:

SizeHorizontal widthVertical height
smmin(100vw, 360px)min(100vh, 240px)
mdmin(100vw, 480px)min(100vh, 360px)
lgmin(100vw, 640px)min(100vh, 480px)
xlmin(100vw, 800px)min(100vh, 640px)
full100vw100vh

If you need an exact size, pass width / height (a CSS length string or number → px). Inline-applied so the vaul measurement is correct on first paint.

Migration note — the default size changed (was hardcoded 280px for left/right, auto for top/bottom). New default is size="md". Pass size="sm" (~360px) for the closest old left/right behavior, or set an explicit width / height.

Navigation (8)

Tabs Accordion Collapsible Command ContextMenu DropdownMenu Menubar NavigationMenu

Data (10)

Table Badge Avatar Progress Calendar Carousel Chart Toggle ToggleGroup DatePicker

Feedback (5)

Alert Toaster (Sonner) Spinner Empty Preloader

Specialized (7)

Kbd TokenIcon Item Portal ImageWithFallback CopyButton CopyField

Hooks (30+)

Hooks are organized by domain inside the package (src/hooks/<group>/). Public import path is the single barrel:

import { useIsMobile, useScroll, useNavigate } from '@djangocfg/ui-core/hooks';

dom/ — DOM & viewport

HookDescription
useScroll(target?)Reactive { x, y, direction, isScrolling } for window or any scrollable element. useSyncExternalStore + module-level shared store + rAF throttle + passive listener.
useScrollPosition(target?) / useScrollDirection(target?) / useIsScrolling(target?)Single-field variants — re-render only when their slice changes.
useBodyScrollLock(locked)Lock body scroll while locked=true; counter-based (multi-consumer safe), iOS-safe via position: fixed fallback.
useCopyCopy to clipboard.
useImageLoaderImage loading state.

media/ — viewport size

HookDescription
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.

state/ — state primitives

HookDescription
useDebounceDebounce values.
useDebouncedCallbackDebounced callbacks.
useLocalStorage / useSessionStorageType-safe wrappers with TTL.
useStoredValueUnified API over local/session storage.

device/ — environment detection

HookDescription
useBrowserDetectBrowser detection (Chrome, Safari, in-app browsers, etc.).
useDeviceDetectDevice detection (mobile, tablet, desktop, OS, etc.).
useShortcutModLabel()Returns or Ctrl for shortcut hints (Apple vs Windows/Linux); pairs with metaKey || ctrlKey handlers.

Other groups

GroupHooks
feedback/useToast, toast (Sonner).
theme/useResolvedTheme — current resolved theme (light/dark/system).
time/useCountdown, useCountdownFromSeconds.
events/useEventListener, events (PubSub bus).
hotkey/useHotkey, HotkeysProvider (react-hotkeys-hook).
debug/useDebugTools.
router/See Router Hooks below — its own subsection.
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)')

// scroll snapshot — direction-aware navbar
const { direction, isScrolling } = useScroll()
const hideNav = direction === 'down' && isScrolling

Router Hooks

Framework-agnostic navigation primitives — work on plain History API by default, plug into any router via the adapter pattern. Full docs in src/hooks/router/README.md.

HookPurpose
useLocation()Reactive { pathname, search, hash, href }.
useLocationProperty(get, getSsr)Subscribe to ONE field — skip re-renders on unrelated changes.
useNavigate()navigate, navigateExternal, push, replace, back, forward.
useQueryParams()Record-style read/write of ?key=value URL state.
useQueryState(key, parser)Typed useState-style hook bound to one URL key (with clearOnDefault).
useBackOrFallback()Smart Back that falls back to a route when there's no in-app history.
useUrlBuilder()Pure URL assembly: build, withCurrentParams.
useSmartLink(href)Make any element a link (cmd-click, middle-click, Enter, Space).
useIsActive(href)Boolean for nav-item highlighting.
useRouter()Convenience facade composing everything.
RouterAdapterProviderSwap the navigation backend.
parseAsString / parseAsInteger / parseAsFloat / parseAsBoolean / parseAsIsoDate / parseAsStringEnum / parseAsArrayOf / parseAsJsonParsers for useQueryState. Each has .withDefault(value).
import {
  useNavigate,
  useQueryState,
  parseAsInteger,
} from '@djangocfg/ui-core/hooks';

const { navigate } = useNavigate();
const [page, setPage] = useQueryState('page', parseAsInteger.withDefault(1));

navigate('/products');
setPage((p) => p + 1);  // ?page=2 — `page=1` is dropped (clearOnDefault)

Next.js adapter

In Next apps, mount both adapters once near the root so navigation flows through next/navigation (server components + prefetch keep working) and <Link> delegates to next/link:

import { NextRouterAdapter, NextLinkProvider } from '@djangocfg/ui-core/adapters/nextjs';

<NextRouterAdapter>
  <NextLinkProvider>
    <App />
  </NextLinkProvider>
</NextRouterAdapter>

next is an optional peer dependency — Wails / Electron / Vite consumers don't pull it in. @djangocfg/layouts/BaseApp mounts both adapters automatically.

Theme Palette Hooks

Hooks for accessing theme colors from CSS variables (useful for Canvas, SVG, charts, diagrams, etc.):

Hook / UtilDescription
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

Zustand-powered dialog service replacing native window.alert, window.confirm, window.prompt with shadcn dialogs. Also provides window.dialog.auth() for triggering authentication dialogs.

import { DialogProvider, useDialog } from '@djangocfg/ui-core/lib/dialog-service';

// Wrap your app with DialogProvider (already included in BaseApp)
function App() {
  return (
    <DialogProvider>
      <YourApp />
    </DialogProvider>
  );
}

// Use via React hook
function Component() {
  const { alert, confirm, prompt, auth } = useDialog();

  const handleDelete = async () => {
    const confirmed = await confirm({
      title: 'Delete item?',
      message: 'This action cannot be undone.',
      variant: 'destructive',
    });
    if (confirmed) {
      // Delete...
    }
  };

  const handleProtected = async () => {
    const didAuth = await auth({ message: 'Please sign in to continue' });
    if (didAuth) {
      // User navigated to auth
    }
  };
}

// Or use globally from anywhere (vanilla JS, libraries, etc.)
window.dialog.alert({ message: 'Hello!' });
const ok = await window.dialog.confirm({ message: 'Are you sure?' });
const name = await window.dialog.prompt({ message: 'Enter your name:' });
const didAuth = await window.dialog.auth({ message: 'Session expired' });

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

PathContent
@djangocfg/ui-coreAll components & hooks
@djangocfg/ui-core/componentsComponents only
@djangocfg/ui-core/hooksHooks only (incl. router hooks)
@djangocfg/ui-core/adapters/nextjs<NextRouterAdapter> + <NextLinkProvider> for Next.js apps (optional peer: next)
@djangocfg/ui-core/libUtilities (cn, etc.)
@djangocfg/ui-core/lib/dialog-serviceDialog service
@djangocfg/ui-core/utilsRuntime utilities (emitRuntimeError)
@djangocfg/ui-core/stylesCSS
@djangocfg/ui-core/styles/paletteTheme 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' });
}

<Link> and <ButtonLink> ship in ui-core itself — no Next.js required. Default behavior renders <a> and routes clicks through useNavigate.

In Next.js apps, mount NextLinkProvider (from @djangocfg/ui-core/adapters/nextjs) near the root and the same components delegate to next/link automatically. @djangocfg/layouts/BaseApp does this for you.

import { Link, ButtonLink } from '@djangocfg/ui-core/components';

<Link href="/about">About</Link>
<ButtonLink href="/docs" variant="outline">Docs</ButtonLink>

What's NOT included (use ui-nextjs)

These features require Next.js or browser storage APIs:

  • Sidebar'use client' heavy, lives in ui-nextjs
  • Breadcrumb, BreadcrumbNavigation — same
  • Pagination, SSRPagination — same
  • DownloadButton — uses localStorage
  • useTheme — uses next-themes

Requirements

  • React >= 18 or >= 19
  • Tailwind CSS >= 4

Full documentation & examples

Keywords

ui-components

FAQs

Package last updated on 25 Apr 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts