Theme Customization Guide
DayFlow Calendar's appearance is controlled by a set of namespaced CSS custom properties (--df-color-*). All tokens are defined inside @layer df-theme, so host applications can override them without !important — regardless of whether they use Tailwind or plain CSS.
DayFlow's shared foundation CSS is the single source of truth for theme tokens, component primitives, and semantic helper classes such as df-fill-primary and df-focus-ring.
Table of Contents
- Custom Calendar Type Colors
- CSS Variable Reference
- Override Methods
- Tailwind v4 Integration
- Creating a Custom Theme
Custom Calendar Type Colors
Basic Custom Colors
Define unique colors for each calendar type with separate light and dark variants:
const calendar = useCalendarApp({
calendarTypes: [
{
id: 'personal',
name: 'Personal',
colors: {
lineColor: '#0891b2', // cyan-600
eventColor: '#cffafe', // cyan-100
eventSelectedColor: '#a5f3fc', // cyan-200
textColor: '#164e63', // cyan-900
},
darkColors: {
lineColor: '#22d3ee', // cyan-400
eventColor: '#164e63', // cyan-900
eventSelectedColor: '#083344', // cyan-950
textColor: '#cffafe', // cyan-100
},
},
],
});Color Properties Explained
- lineColor: Border and accent color (left bar on events)
- eventColor: Event background fill
- eventSelectedColor: Background fill when an event is selected
- textColor: Text color for event title and time
Brand Color Integration
{
id: 'brand',
name: 'Brand Events',
colors: {
lineColor: '#6366f1', // Brand indigo
eventColor: '#e0e7ff', // Indigo-100
eventSelectedColor: '#c7d2fe', // Indigo-200
textColor: '#312e81', // Indigo-900
},
darkColors: {
lineColor: '#a5b4fc', // Indigo-300
eventColor: '#312e81', // Indigo-900
eventSelectedColor: '#1e1b4b', // Indigo-950
textColor: '#e0e7ff', // Indigo-100
},
}Color Generation Helper
// utils/colorGenerator.ts
interface ColorSet {
lineColor: string;
eventColor: string;
eventSelectedColor: string;
textColor: string;
}
export function generateLightColors(baseColor: string): ColorSet {
return {
lineColor: baseColor,
eventColor: lighten(baseColor, 0.9),
eventSelectedColor: lighten(baseColor, 0.8),
textColor: darken(baseColor, 0.4),
};
}
export function generateDarkColors(baseColor: string): ColorSet {
return {
lineColor: lighten(baseColor, 0.3),
eventColor: darken(baseColor, 0.6),
eventSelectedColor: darken(baseColor, 0.7),
textColor: lighten(baseColor, 0.8),
};
}CSS Variable Reference
All DayFlow theme tokens use the --df-color- prefix to avoid collisions with any host application variables.
| Variable | Purpose |
|---|---|
--df-color-background | Calendar background |
--df-color-foreground | Primary text color |
--df-color-hover | Hover state background |
--df-color-border | Borders and dividers |
--df-color-card | Card / panel background |
--df-color-card-foreground | Card text color |
--df-color-muted | Subtle background areas |
--df-color-muted-foreground | Muted / secondary text |
--df-color-primary | Primary accent (buttons, selected states) |
--df-color-primary-foreground | Text on primary-colored backgrounds |
--df-color-secondary | Secondary accent |
--df-color-secondary-foreground | Text on secondary-colored backgrounds |
--df-color-destructive | Destructive actions |
--df-color-destructive-foreground | Text on destructive backgrounds |
Semantic Helper Classes
In addition to CSS variables, DayFlow now exposes theme-aware semantic helper classes. These are useful when you render custom content inside slots, plugin UI, or wrappers that should visually match the built-in controls.
| Class Name | Meaning |
|---|---|
df-fill-primary | Primary filled surface with automatic foreground text |
df-fill-secondary | Secondary filled surface with automatic foreground text |
df-fill-destructive | Destructive filled surface with automatic foreground text |
df-tint-primary | Subtle primary selection tint |
df-hover-primary | Primary-themed hover state |
df-hover-primary-solid | Hover state for filled primary buttons |
df-text-primary | Primary text color |
df-border-primary | Primary border color |
df-ring-primary | Primary ring color token |
df-focus-ring | Focus helper that applies both primary border and ring |
Prefer these df-* helpers or --df-color-* overrides when styling DayFlow. Avoid depending on old internal Tailwind semantic names such as bg-primary, text-primary, or hover:bg-primary/90.
Override Methods
Method 1 — Container-level override (works everywhere)
Set variables directly on .df-calendar-container. Because this rule is outside any @layer, it always wins over the library's defaults regardless of Tailwind version or CSS setup.
In practice, you will often want to target both .df-calendar-container and .df-portal:
.df-calendar-containeris the root container for the visible calendar surface.df-portalis the root class DayFlow uses for floating UI rendered via portals intodocument.body, such as dialogs, dropdowns, and some picker panels
If you only override .df-calendar-container, the main calendar can pick up your theme while portal-based overlays may still use the default tokens.
/* styles/globals.css */
.df-calendar-container,
.df-portal {
--df-color-primary: #6366f1;
--df-color-background: #f9fafb;
--df-color-border: #e0e7ff;
}
/* Dark mode — target the container when the .dark class is on an ancestor */
.dark .df-calendar-container,
.dark .df-portal {
--df-color-primary: #a5b4fc;
--df-color-background: #1e1e2e;
--df-color-border: #312e81;
}This is the recommended approach for most projects. The variables are scoped to the calendar and do not affect anything outside it.
Tailwind v4 Integration
Tailwind v4 is configured entirely through CSS — there is no tailwind.config.js. DayFlow's distributed CSS already includes the shared foundation layer, so theme tokens and semantic helper classes are available immediately after import.
Choosing the right CSS file
DayFlow ships two CSS bundles:
| File | Contents | Use when |
|---|---|---|
styles.css | Full bundle including Tailwind preflight (CSS reset) | Not using Tailwind |
styles.components.css | Component styles only, no CSS reset | Already using Tailwind |
Minimal setup
/* app.css — for Tailwind projects */
@import '@dayflow/core/dist/styles.components.css';
@import 'tailwindcss';If your project does not use Tailwind, import the full bundle instead:
/* app.css — for non-Tailwind projects */
@import '@dayflow/core/dist/styles.css';Dark mode
DayFlow respects the .dark class on any ancestor element (including <html>). Apply it with JavaScript:
document.documentElement.classList.toggle('dark', isDark);System-preference dark mode (no explicit class) is also supported automatically.
Using theme.mode with Tailwind v4
DayFlow's distributed CSS already includes the .dark variant it needs for theme.mode. In Tailwind v4 projects, importing @dayflow/core/dist/styles.components.css is enough for DayFlow itself to respond to the .dark class on <html>.
If you also want your app's own Tailwind dark: utilities to follow the same class toggle, add the class-based variant in your CSS entry:
@import '@dayflow/core/dist/styles.components.css';
@import 'tailwindcss';
/* Optional: only needed for your app's own Tailwind dark: utilities */
@variant dark (.dark &);Without this extra line, DayFlow still switches correctly via theme.mode; only your own Tailwind dark: utilities stay on Tailwind's default media-query behavior.
Practical recommendation
For most apps, use this order of precedence:
- Override
--df-color-*tokens on.df-calendar-container,.df-portal, or your own wrapper. - Reuse DayFlow's semantic helpers such as
df-fill-primaryanddf-focus-ringin custom slot/plugin markup. - Only reach for low-level utility overrides when you are changing layout rather than theme.
Applying overrides with @theme
@import '@dayflow/core/dist/styles.css' layer(dayflow);
@import 'tailwindcss';
@theme {
--df-color-primary: #6366f1;
--df-color-primary-foreground: #ffffff;
--df-color-secondary: #8b5cf6;
--df-color-secondary-foreground: #ffffff;
}Wrapping the calendar with Tailwind utilities
function ThemedCalendar({ calendar }) {
return (
<div className='rounded-2xl shadow-xl ring-1 ring-gray-200 dark:ring-gray-700'>
<DayFlowCalendar calendar={calendar} />
</div>
);
}Creating a Custom Theme
// themes/oceanTheme.ts
export const oceanTheme = {
mode: 'light' as const,
calendarTypes: [
{
id: 'deep-ocean',
name: 'Deep Ocean',
colors: {
lineColor: '#0369a1',
eventColor: '#e0f2fe',
eventSelectedColor: '#bae6fd',
textColor: '#0c4a6e',
},
darkColors: {
lineColor: '#7dd3fc',
eventColor: '#0c4a6e',
eventSelectedColor: '#083344',
textColor: '#e0f2fe',
},
},
{
id: 'coral-reef',
name: 'Coral Reef',
colors: {
lineColor: '#ea580c',
eventColor: '#ffedd5',
eventSelectedColor: '#fed7aa',
textColor: '#7c2d12',
},
darkColors: {
lineColor: '#fb923c',
eventColor: '#7c2d12',
eventSelectedColor: '#431407',
textColor: '#ffedd5',
},
},
],
};Pair it with CSS variable overrides for full visual consistency:
/* Ocean theme CSS tokens */
.df-calendar-container {
--df-color-primary: #0369a1;
--df-color-background: #f0f9ff;
--df-color-border: #bae6fd;
}
.dark .df-calendar-container {
--df-color-primary: #7dd3fc;
--df-color-background: #0c1220;
--df-color-border: #0c4a6e;
}Resources
Tools
- WebAIM Contrast Checker - Test color contrast
- Coolors - Generate color palettes
- Color Contrast Analyzer - Desktop tool
Libraries
- chroma-js - Color manipulation
- tinycolor2 - Color utilities
- color - Color conversion
Tailwind Resources
- Tailwind v4 Upgrade Guide - v3 → v4 migration
- Tailwind CSS Layers - Layer documentation
Related Documentation
- Dark Mode - Dark mode overview and API
- Calendar Types - Event categorization
- Use Calendar App - Core configuration