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

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.

VariablePurpose
--df-color-backgroundCalendar background
--df-color-foregroundPrimary text color
--df-color-hoverHover state background
--df-color-borderBorders and dividers
--df-color-cardCard / panel background
--df-color-card-foregroundCard text color
--df-color-mutedSubtle background areas
--df-color-muted-foregroundMuted / secondary text
--df-color-primaryPrimary accent (buttons, selected states)
--df-color-primary-foregroundText on primary-colored backgrounds
--df-color-secondarySecondary accent
--df-color-secondary-foregroundText on secondary-colored backgrounds
--df-color-destructiveDestructive actions
--df-color-destructive-foregroundText 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 NameMeaning
df-fill-primaryPrimary filled surface with automatic foreground text
df-fill-secondarySecondary filled surface with automatic foreground text
df-fill-destructiveDestructive filled surface with automatic foreground text
df-tint-primarySubtle primary selection tint
df-hover-primaryPrimary-themed hover state
df-hover-primary-solidHover state for filled primary buttons
df-text-primaryPrimary text color
df-border-primaryPrimary border color
df-ring-primaryPrimary ring color token
df-focus-ringFocus 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-container is the root container for the visible calendar surface
  • .df-portal is the root class DayFlow uses for floating UI rendered via portals into document.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:

FileContentsUse when
styles.cssFull bundle including Tailwind preflight (CSS reset)Not using Tailwind
styles.components.cssComponent styles only, no CSS resetAlready 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:

Utility class scanning (@source)

DayFlow's components still use Tailwind utility classes (flex, bg-white, text-gray-600, etc.) internally for layout and neutral styling. Your project's Tailwind instance must generate those classes by scanning DayFlow's files. The old semantic Tailwind names (bg-primary, text-primary, etc.) are no longer required by DayFlow internals.

When you import @dayflow/core/dist/styles.components.css, Tailwind still needs to scan DayFlow's published JavaScript files to discover the utility classes used inside the library. Tailwind's automatic source detection does not scan node_modules, so this @source step is required even with Vite + @tailwindcss/vite.

Add @source directives in your CSS entry file:

@import '@dayflow/core/dist/styles.components.css';
@import 'tailwindcss';

/* Required when consuming the published npm package */
@source '../node_modules/@dayflow/core/dist/**/*.js';
@source '../node_modules/@dayflow/plugin-drag/dist/**/*.js'; /* if using drag plugin */
@source '../node_modules/@dayflow/plugin-sidebar/dist/**/*.js'; /* if using sidebar plugin */

Without this, Tailwind will not generate many of the utility classes used inside DayFlow's components and the UI will appear partially or completely unstyled.

If you are working against a local DayFlow workspace checkout instead of the published npm package, point @source at the relevant workspace source directories 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

Tailwind v4 compiles dark: utility classes as @media (prefers-color-scheme: dark) by default. DayFlow's theme.mode works by adding the .dark class to <html> — so if your Tailwind instance uses media-query dark mode, those dark: utilities inside DayFlow's components will not respond to the class change.

Add this to your CSS entry file to switch Tailwind to class-based dark mode:

@import '@dayflow/core/dist/styles.components.css';
@import 'tailwindcss';

/* Required for theme.mode to work: make dark: utilities respond to .dark class */
@variant dark (.dark &);

Without this, theme.mode: 'dark' will still update the CSS custom properties (--df-color-*) correctly, but Tailwind's dark: utility classes inside DayFlow's components will only activate when the system preference is dark.

Practical recommendation

For most apps, use this order of precedence:

  1. Override --df-color-* tokens on .df-calendar-container, .df-portal, or your own wrapper.
  2. Reuse DayFlow's semantic helpers such as df-fill-primary and df-focus-ring in custom slot/plugin markup.
  3. 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

Libraries

Tailwind Resources

On this page