UI Component System
Relevant source files
The following files were used as context for generating this wiki page:
The Heyme UI Component System is a collection of reusable, styled React components built to ensure a consistent and accessible user interface across the application. It is built upon a modern frontend stack, leveraging Radix UI primitives for accessibility and unstyled functionality, and styled with Tailwind CSS. This system provides foundational elements like dialogs, menus, and tabs, all supporting features like dark mode out of the box.
The architecture emphasizes composition, allowing developers to construct complex UI elements from smaller, focused components. Utility libraries like class-variance-authority and clsx are used to manage component styling variants and conditional classes efficiently.
Core Technologies and Architecture
The UI system is built on several key libraries that work together to provide a flexible and robust component foundation.
Sources: package.json
Core Dependencies
The following table outlines the primary libraries used in the UI component system and their roles.
| Library | Purpose |
|---|---|
react | The core library for building the user interface. |
next | The React framework providing structure, routing, and server-side rendering. |
@radix-ui/* | A collection of unstyled, accessible UI primitives (e.g., @radix-ui/react-dialog, @radix-ui/react-tabs). These form the functional base of the components. |
tailwindcss | A utility-first CSS framework used for all styling. |
class-variance-authority | A library for creating type-safe, variant-based component styles with Tailwind CSS. |
clsx & tailwind-merge | Utilities for conditionally joining class names and merging Tailwind CSS classes without style conflicts. They are combined in a cn utility function. |
next-themes | Manages theme switching, enabling light and dark modes. |
lucide-react | Provides the icon set used within components. |
Sources: package.json:20-56, components/ui/dialog.tsx:4, pages/_app.tsx:5
Technology Stack Overview
This diagram illustrates the hierarchy of technologies that form the UI component system.
This diagram shows that custom UI components are built in React on top of the Next.js framework, using Radix UI for functionality and Tailwind CSS for styling, assisted by several utilities.
Sources: package.json, components/ui/dialog.tsx, components/ui/navigation-menu.tsx
Styling and Theming
Styling is managed through a combination of Tailwind CSS for utility classes and class-variance-authority for component variants. A custom cn utility function is used throughout the components to merge classes.
Dark Mode
Dark mode is implemented using next-themes. The ThemeProvider is wrapped around the application in _app.tsx, and the dark class is applied to the <html> element, enabling Tailwind's dark: variants.
pages/_app.tsx: TheThemeProvidercomponent is configured withattribute="class".pages/_document.tsx: The<html>tag is initialized withclassName="dark"andstyle={{ colorScheme: 'dark' }}to set the default theme.- Component Styles: Components use
dark:prefixed utility classes (e.g.,dark:bg-slate-900) to apply styles when dark mode is active.
Sources: pages/_app.tsx:24-26, pages/_document.tsx:5, components/ui/dialog.tsx:52
Component Variants
The class-variance-authority (CVA) library is used to define different visual variants of a component. For example, the NavigationMenuTrigger uses a cva function to define its base styles.
// components/ui/navigation-menu.tsx:32-34
const navigationMenuTriggerStyle = cva(
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus:outline-none focus:bg-slate-100 disabled:opacity-50 dark:focus:bg-slate-800 disabled:pointer-events-none bg-transparent hover:bg-slate-100 dark:hover:bg-slate-800 dark:text-slate-100 dark:hover:text-slate-100 data-[state=open]:bg-slate-50 dark:data-[state=open]:bg-slate-800 h-10 py-2 px-4 group"
)
This approach is also used for buttonVariants, which are consumed in components like SiteHeader to apply consistent button styling without directly using the Button component.
Sources: components/ui/navigation-menu.tsx:32-34, components/site-header.tsx:8, 26
Component Architecture
The UI components follow a consistent architectural pattern based on composition and forwarding React props and refs.
Composition with Radix UI
Each custom UI component is a thin wrapper around a corresponding Radix UI primitive. This pattern involves:
- Importing the necessary parts from the Radix UI library (e.g.,
* as DialogPrimitive from "@radix-ui/react-dialog"). - Creating new React components that forward their props (
...props) andrefto the Radix component. - Applying styles using the
cnutility function, which combines base classes with anyclassNameprop passed in.
The following diagram shows the composition of the Dialog component.
This diagram illustrates how custom Dialog components wrap and extend the functionality of the underlying DialogPrimitive components from Radix UI.
Sources: components/ui/dialog.tsx
Example: Dialog Component Breakdown
The Dialog component is a prime example of the system's architecture. It is broken down into several composable parts.
| Component | Role | Radix Primitive |
|---|---|---|
Dialog | The root container for the dialog. | DialogPrimitive.Root |
DialogTrigger | The element that opens the dialog when clicked. | DialogPrimitive.Trigger |
DialogContent | The main content of the dialog window. It includes an overlay and positioning logic. | DialogPrimitive.Content |
DialogHeader | A container for the dialog's title and description. | div |
DialogFooter | A container for action buttons (e.g., Save, Cancel). | div |
DialogTitle | The title of the dialog. | DialogPrimitive.Title |
DialogDescription | The description or subtext of the dialog. | DialogPrimitive.Description |
This compositional approach allows for great flexibility in how dialogs are constructed.
The flow of opening a dialog is managed by Radix internally.
This sequence shows that a user click on the DialogTrigger causes the DialogContent to be rendered and displayed.
Sources: components/ui/dialog.tsx:8-112
Component Showcase
The system includes a wide range of components. Below are a few examples.
Tabs
Provides a set of tabbed content panels. It is composed of Tabs, TabsList, TabsTrigger, and TabsContent.
Tabs: The root component.TabsList: The container for the tab buttons.TabsTrigger: An individual tab button.TabsContent: The content panel associated with a trigger.
Styling is applied to differentiate the active tab (data-[state=active]).
Sources: components/ui/tabs.tsx
Select (Dropdown)
A customizable select/dropdown component. It is composed of Select, SelectTrigger, SelectContent, and SelectItem.
Select: The root component.SelectTrigger: The button that opens the dropdown.SelectContent: The floating panel containing the options.SelectItem: An individual option in the list. An indicator (<Check />) is shown for the selected item.
Sources: components/ui/select.tsx
NavigationMenu
A complex menu component for site navigation, supporting dropdowns and custom content areas.
NavigationMenu: The root container.NavigationMenuList: A list of menu items.NavigationMenuItem: An individual item in the list.NavigationMenuTrigger: An element that opens a submenu, often decorated with a chevron icon.NavigationMenuContent: The content of the dropdown/submenu.
This component uses data-[state=open] selectors and animations for showing and hiding content.
Sources: components/ui/navigation-menu.tsx
Conclusion
The Heyme UI Component System provides a powerful and consistent foundation for the application's interface. By building on top of Radix UI and Tailwind CSS, it ensures accessibility, functionality, and a consistent design language. The compositional nature of the components allows for flexibility and reusability, while the integration of next-themes provides a seamless dark mode experience. This well-structured system is crucial for maintaining UI quality and developer velocity.