Skip to Content
FrontendRecipesUI Components

UI Components

The UI layer is split into four packages built on Radix primitives and Tailwind CSS v4.

For Tailwind v4 migration details and CSS config see Tailwind v4 recipe.

Package Hierarchy

@djangocfg/ui-core Pure React (133 components, Radix + Tailwind v4) └── @djangocfg/ui-nextjs Next.js extensions (Link, Sidebar, Pagination, SSR) └── @djangocfg/ui-tools Heavy tools, lazy-loaded (maps, mermaid, code, video, audio) └── @djangocfg/layouts App layouts (Public, Private, Auth, Admin, Dashboard)

In Next.js apps always import from @djangocfg/ui-nextjs, not @djangocfg/ui-core directly. ui-nextjs re-exports everything from ui-core plus Next.js-specific components.

Component Categories

CategoryCountExamples
Forms23Button, Input, Select, Combobox, MultiSelect, Switch, Slider, PhoneInput
Layout14Card, Sidebar, ScrollArea, Resizable, Skeleton, Separator
Navigation6Breadcrumb, Tabs, Pagination, NavigationMenu
Overlay9Dialog, Sheet, Drawer, Popover, Tooltip, DropdownMenu
Feedback4Alert, Badge, Progress, Toaster (sonner)
Data Display9Table, Accordion, Calendar, DatePicker, SSRPagination
Interactive3Command (cmdk), Toggle, ToggleGroup
Charts7ChartContainer + recharts (Area, Bar, Line, Pie, Donut, Radial)
Hooks15useDebounce, useHotkey, useLocalStorage, useMediaQuery, useIsMobile
LayoutsBaseApp (providers) + PrivateLayout / PublicLayout / AuthLayout (shells)

Import Patterns

// Components — ui-core is framework-agnostic, import directly import { Button, Card, Badge, Dialog } from '@djangocfg/ui-core/components'; import { Sidebar, SidebarProvider, useSidebar } from '@djangocfg/ui-core/components'; // Hooks import { useDebounce, useHotkey, useLocalStorage } from '@djangocfg/ui-core/hooks'; import { useQueryParams } from '@djangocfg/ui-core/hooks'; // Next.js router adapter (Next apps only) import { NextRouterAdapter } from '@djangocfg/ui-core/adapters/nextjs'; // Layouts — BaseApp = providers (mount once); shells per route-group import { BaseApp, PrivateLayout, PublicLayout, AuthDialog } from '@djangocfg/layouts'; import { AIChatWidget, AIChatProvider } from '@djangocfg/layouts/snippets'; // Heavy tools (lazy-loaded) import { LazyMermaid } from '@djangocfg/ui-tools/mermaid'; import { LazyPrettyCode } from '@djangocfg/ui-tools/pretty-code'; import { LazyJsonTree } from '@djangocfg/ui-tools/json-tree'; import { GalleryCompact } from '@djangocfg/ui-tools/gallery';

DRF Pagination

Integrate DRF paginated responses with the pagination component:

import { SSRPagination, useDRFPagination } from '@djangocfg/ui-nextjs'; const { page, pageSize, setPage, setPageSize, paginationInfo } = useDRFPagination({ total: data?.count ?? 0, defaultPageSize: 20, }); <SSRPagination currentPage={page} totalPages={paginationInfo.totalPages} onPageChange={setPage} />

useDRFPagination converts DRF’s count field into page info and provides setter functions.

Full sidebar with 17 exports for building navigation:

<SidebarProvider> <Sidebar> <SidebarHeader> <SidebarMenu> <SidebarMenuItem> <SidebarMenuButton>Dashboard</SidebarMenuButton> </SidebarMenuItem> </SidebarMenu> </SidebarHeader> <SidebarContent> <SidebarGroup> <SidebarGroupLabel>Main</SidebarGroupLabel> <SidebarGroupContent> <SidebarMenu> <SidebarMenuItem> <SidebarMenuButton>Catalog</SidebarMenuButton> </SidebarMenuItem> </SidebarMenu> </SidebarGroupContent> </SidebarGroup> </SidebarContent> <SidebarFooter>...</SidebarFooter> </Sidebar> </SidebarProvider>

Rules

  1. Import directly from @djangocfg/ui-core (framework-agnostic); in Next.js add the @djangocfg/ui-core/adapters/nextjs router adapter
  2. Use @djangocfg/ui-tools for heavy components (maps, code, mermaid) — they are lazy-loaded
  3. Use @djangocfg/layouts for app-level chrome: BaseApp (providers, once at root) + PrivateLayout / PublicLayout (shells, per route-group)
  4. Use useDRFPagination to convert DRF count responses into page state — do not compute pages manually
  5. Wrap sidebar navigation with SidebarProvider — use useSidebar() for programmatic open/close
Last updated on