tremorlabs/tremor
Copy & Paste React components to build modern web applications.
Component library that provides accessible React UI components for dashboard applications
Props flow from parent components through the component tree, where each Tremor component receives standard React props plus variant-specific props. The cx utility merges these classes with default styles, tailwind-variants generates conditional CSS based on variant props, and the final className is passed to either a native DOM element or a Radix UI primitive. Radix primitives handle accessibility features while Tremor adds consistent visual design.
Under the hood, the system uses 2 data pools, 3 control points to manage its runtime behavior.
A 8-component library. 139 files analyzed. Data flows through 4 distinct pipeline stages.
How Data Flows Through the System
Props flow from parent components through the component tree, where each Tremor component receives standard React props plus variant-specific props. The cx utility merges these classes with default styles, tailwind-variants generates conditional CSS based on variant props, and the final className is passed to either a native DOM element or a Radix UI primitive. Radix primitives handle accessibility features while Tremor adds consistent visual design.
- Props Reception — Component receives props including className overrides, variant selections (size, color, etc.), disabled state, and standard React props like children and event handlers through forwardRef [ComponentProps]
- Variant Processing — tailwind-variants tv() function receives variant prop values and generates base CSS classes plus variant-specific classes using conditional logic defined in the component's variant configuration [ComponentProps → VariantConfig]
- Style Composition — cx utility function merges generated variant classes with user-provided className prop using clsx for conditional application and tailwind-merge for CSS precedence resolution [VariantConfig → ClassValue]
- Component Rendering — Final merged className is applied to either a Radix UI primitive (for complex components like Switch, Accordion) or a native DOM element, with props forwarded through React.forwardRef for ref handling [ClassValue]
Data Models
The data structures that flow between stages — the contracts that hold the system together.
src/components/Button/Button.tsxReact.ComponentPropsWithoutRef<T> extended with variant props - includes className: string, disabled: boolean, size/variant discriminated unions, children: ReactNode, and forwarded refs
Props are passed from parent components, merged with default variants using tailwind-variants, and forwarded to the underlying DOM element or Radix primitive
src/components/Button/Button.tsxtailwind-variants tv() configuration object with base: string[], variants: Record<string, Record<string, string[]>>, defaultVariants: Record<string, string>
Defined statically per component, receives variant prop values at runtime, generates final CSS class strings using conditional logic
src/utils/cx.tsUnion type from clsx accepting string | object | array | undefined - represents any valid CSS class input that can be conditionally applied
Class values are collected from component variants and user overrides, merged using clsx for conditional logic, then deduplicated with tailwind-merge for CSS precedence
Hidden Assumptions
Things this code relies on but never validates. These are the things that cause silent failures when the system changes.
The cx function assumes all input ClassValue arguments are valid Tailwind CSS classes that tailwind-merge can understand and deduplicate correctly
If this fails: If non-Tailwind CSS classes or malformed class strings are passed, tailwind-merge may silently ignore them or produce unexpected class combinations, leading to broken styling without any error indication
src/utils/cx.ts:cx
Assumes Tailwind CSS is configured with the exact color palette and utilities referenced (blue-500, gray-300, etc.) and that dark mode is enabled via the 'dark:' prefix
If this fails: If Tailwind config is missing these colors or dark mode support, components render with broken styling - missing colors appear as plain text, dark mode styles are ignored, but no runtime errors occur
src/components/Button/Button.tsx:buttonVariants
The Switch component assumes Radix UI SwitchPrimitives.Root provides data-[state=checked] and data-[state=unchecked] attributes that CSS selectors depend on for visual state changes
If this fails: If Radix UI changes these data attribute names in future versions, the switch will render but state-dependent styling (colors, thumb position) will break completely, leaving a non-functional looking component
src/components/Switch/Switch.tsx:Switch
Assumes the returned domain tuple [minDomain, maxDomain] where values can be either 'auto' strings or numbers will be consumed by a charting library that understands this mixed-type format
If this fails: If the consuming chart library expects consistent types (all numbers or all strings), it may crash, render incorrectly, or ignore the domain values entirely, breaking chart scaling behavior
src/utils/getYAxisDomain.ts:getYAxisDomain
When asChild=true, assumes the children prop contains exactly one React element that Radix Slot can clone and merge props into
If this fails: If children contains multiple elements, text nodes, or null values when asChild=true, Radix Slot throws runtime errors or renders nothing, breaking the component completely
src/components/Card/Card.tsx:Card
Assumes the consuming environment supports CSS outline-offset and focus-visible pseudo-class, which are relatively modern CSS features
If this fails: In older browsers or environments without focus-visible support, focus indicators may not appear at all, creating accessibility violations for keyboard navigation
src/utils/focusRing.ts:focusRing
The disabled prop on Label assumes consumers will coordinate this state with associated form controls, but Label itself has no mechanism to enforce or validate this relationship
If this fails: Labels can appear disabled while their associated inputs remain enabled (or vice versa), creating confusing UX where visual state doesn't match functional state
src/components/Label/Label.tsx:Label
Switch size variants hardcode specific pixel values for width/height (h-5 w-9, h-4 w-7) and translation distances (translate-x-4, translate-x-3) assuming standard Tailwind spacing scale
If this fails: If Tailwind spacing is customized or components need different sizing, the thumb translation may not align properly with the track, creating visual misalignment where the thumb doesn't reach track edges
src/components/Switch/Switch.tsx:switchVariants
Assumes tailwind-merge's internal cache can handle the volume of className combinations without memory issues or significant performance degradation
If this fails: In applications with many dynamic class combinations or long-running sessions, the cache could grow large enough to cause memory pressure or GC overhead, degrading UI responsiveness
src/utils/cx.ts:cx
Storybook configuration assumes all component stories follow the naming pattern *.stories.@(js|jsx|mjs|ts|tsx) and are located under src/**/ directories
If this fails: Stories placed in other locations or using different naming conventions won't be discovered by Storybook, making components appear missing from the development environment without clear error messages
.storybook/main.ts:config
System Behavior
How the system operates at runtime — where data accumulates, what loops, what waits, and what controls what.
Data Pools
Each component defines its variant configurations using tailwind-variants tv() - maps variant prop combinations to CSS class arrays
tailwind-merge maintains internal cache of CSS class precedence rules to avoid recomputing class merging logic
Delays
- Style Computation (compilation, ~runtime) — CSS class strings are computed on each render - tailwind-merge performs string parsing and deduplication
- Storybook Hot Reload (compilation, ~1-2s) — Component changes trigger Storybook rebuild and browser refresh for development feedback
Control Points
- Variant Defaults (architecture-switch) — Controls: Default appearance of components when no variant props are provided. Default: size: default, variant: primary
- Dark Mode Support (feature-flag) — Controls: CSS classes include dark: prefixed alternatives for dark theme support. Default: enabled
- Focus Ring Style (hyperparameter) — Controls: Consistent focus indicator appearance across all interactive components. Default: blue-500 outline
Technology Stack
Provides unstyled, accessible component primitives that Tremor wraps with its design system
CSS utility framework used for all component styling through class composition
Generates conditional CSS classes based on component props - handles variant logic and type safety
Deduplicates and resolves precedence conflicts between Tailwind CSS classes
Conditionally applies CSS classes based on boolean logic and object notation
Development environment for building and documenting components in isolation
End-to-end testing of component behavior and interactions in Storybook
Build tool for development server and production bundling
Key Components
- cx (transformer) — Merges and deduplicates CSS class strings by combining clsx for conditional classes with tailwind-merge for Tailwind CSS precedence rules
src/utils/cx.ts - buttonVariants (factory) — Generates CSS classes for button components based on variant props using tailwind-variants - handles primary/secondary/ghost/destructive styles with size variations
src/components/Button/Button.tsx - Button (adapter) — Wraps HTML button or Radix Slot with Tremor's design system - handles loading states, disabled states, and variant-based styling while maintaining accessibility
src/components/Button/Button.tsx - focusRing (factory) — Provides consistent focus ring styling across all interactive components using CSS outline properties with blue color scheme
src/utils/focusRing.ts - Card (adapter) — Creates container components with consistent border, shadow, and background styling - can render as different HTML elements using Radix Slot when asChild=true
src/components/Card/Card.tsx - Switch (adapter) — Wraps Radix Switch primitive with Tremor styling - handles toggle states, disabled states, and size variants while maintaining keyboard accessibility
src/components/Switch/Switch.tsx - Label (adapter) — Wraps Radix Label primitive with consistent typography and disabled state styling for form inputs
src/components/Label/Label.tsx - getYAxisDomain (transformer) — Calculates Y-axis domain for chart components by determining min/max values based on auto-scaling preferences and user-provided bounds
src/utils/getYAxisDomain.ts
Explore the interactive analysis
See the full architecture map, data flow, and code patterns visualization.
Analyze on CodeSeaRelated Library Repositories
Frequently Asked Questions
What is tremor used for?
Component library that provides accessible React UI components for dashboard applications tremorlabs/tremor is a 8-component library written in TypeScript. Data flows through 4 distinct pipeline stages. The codebase contains 139 files.
How is tremor architected?
tremor is organized into 3 architecture layers: Core Utilities, Component Layer, Development Tooling. Data flows through 4 distinct pipeline stages. This layered structure keeps concerns separated and modules independent.
How does data flow through tremor?
Data moves through 4 stages: Props Reception → Variant Processing → Style Composition → Component Rendering. Props flow from parent components through the component tree, where each Tremor component receives standard React props plus variant-specific props. The cx utility merges these classes with default styles, tailwind-variants generates conditional CSS based on variant props, and the final className is passed to either a native DOM element or a Radix UI primitive. Radix primitives handle accessibility features while Tremor adds consistent visual design. This pipeline design keeps the data transformation process straightforward.
What technologies does tremor use?
The core stack includes Radix UI (Provides unstyled, accessible component primitives that Tremor wraps with its design system), Tailwind CSS (CSS utility framework used for all component styling through class composition), tailwind-variants (Generates conditional CSS classes based on component props - handles variant logic and type safety), tailwind-merge (Deduplicates and resolves precedence conflicts between Tailwind CSS classes), clsx (Conditionally applies CSS classes based on boolean logic and object notation), Storybook (Development environment for building and documenting components in isolation), and 2 more. A focused set of dependencies that keeps the build manageable.
What system dynamics does tremor have?
tremor exhibits 2 data pools (Variant Registry, Utility Cache), 3 control points, 2 delays. These runtime behaviors shape how the system responds to load, failures, and configuration changes.
What design patterns does tremor use?
4 design patterns detected: Radix Primitive Wrapping, Variant-Driven Styling, Forward Ref Pattern, Slot Composition.
Analyzed on April 20, 2026 by CodeSea. Written by Karolina Sarna.