← Documentation

Themes & responsive appearance

Available in core 1.1.6. The theme adapters, responsive day labels, and automatic event contrast documented here are part of the published package. The live examples use this same pinned release.

Automatic event text contrast

eventContrastColor: 'auto' selects black or white text using the relative luminance of the rendered event background, including the existing per-event tint. It is opt-in: unset preserves the theme. A CSS color sets a fixed foreground instead.

Automatic contrast
import { WtsCalendar } from '@wts-calendar/core';
import '@wts-calendar/core/styles/calendar.css';

// The page contains <div id="calendar"></div>.
const container = document.getElementById('calendar')!;
const calendar = new WtsCalendar({
  container,
  view: 'month',
  viewDate: '2026-09-16',
  eventColor: '#143d59',
  eventContrastColor: 'auto',
  events: [{ title: 'Review', start: '2026-09-16T10:00:00Z' }],
});

calendar.setOption('eventContrastColor', '#ffffff'); // fixed color
calendar.setOption('eventContrastColor', undefined); // restore theme styling

Precedence: event textColor/contrastColor → source textColor/contrastColor → global eventTextColor → eventContrastColor. At each event/source level, textColor wins if both aliases are present. An event or source can also explicitly request 'auto'.

Works across Month/DayGrid, TimeGrid, MultiMonth/year, List, and resource event views. Transparent labels use their ancestor surface, not the event's colored dot. An entirely transparent page falls back to white. Theme variables, modern CSS colors, runtime options, and ancestor class/style changes are recalculated after rendering.

Background events and explicitly styled custom-content children are not recolored. Images and gradients keep existing text styling; choose an explicit color for them. Opacity, overlapping layers, blend modes, and custom content still need visual testing. Direct CSSOM stylesheet edits require a rerender.

Option reference →

Responsive day labels

dayNarrowWidth defaults to 100 CSS pixels. A column strictly narrower than the threshold gets compact localized labels; 0 disables the behavior. Invalid, negative, or non-finite values are rejected.

Responsive day columns
import { WtsCalendar } from '@wts-calendar/core';
import '@wts-calendar/core/styles/calendar.css';

const container = document.getElementById('calendar')!;
const calendar = new WtsCalendar({
  container,
  dayNarrowWidth: 100, // default, in CSS pixels
  dayHeaderClassNames: ({ isNarrow }) => isNarrow ? 'compact-heading' : '',
});

calendar.setOption('dayNarrowWidth', 120);
calendar.setOption('dayNarrowWidth', 0); // disable compact labels

Month/DayGrid and MultiMonth/year use narrow weekdays and unpadded dates. Week TimeGrid uses stacked weekday/date labels; the optional Day header uses an abbreviated date. Each month panel is measured independently. Full accessible dates, event data, and focus remain intact. Explicit weekDaysFormat and custom content still take precedence; date hooks receive isNarrow.

This does not shrink columns or remove TimeGrid's 112px minimum day width; try a 120px threshold there. List/resource layouts are not given automatic compact date formats. Live resizing uses ResizeObserver; without it only initial sizing is detected.

Option reference →

First-party design-system adapters

These optional, Standard integrations map your app's theme tokens onto WTS controls. They do not replace them with native MUI, shadcn/Radix, or Angular Material components. Keep the global calendar CSS import. Adapters are separate entry points, not separate framework wrappers or automatically enabled plugins. Your themeTokens overrides win.

MUI

Call createMuiCalendarTheme inside your app's ThemeProvider. It maps palette, fonts, shape, shadows, and direction. theme.vars takes precedence when available. For plain themes, pass the new adapter result through options when the provider changes; initialOptions alone is mount-only.

MUI / React
import { useMemo } from 'react';
import { useTheme } from '@mui/material/styles';
import { WtsCalendarReact } from '@wts-calendar/react';
import { createMuiCalendarTheme } from '@wts-calendar/core/theme-mui';
import '@wts-calendar/core/styles/calendar.css';

// Render inside your existing MUI ThemeProvider.
export function Calendar() {
  const theme = useTheme();
  const appearance = useMemo(() => createMuiCalendarTheme(theme), [theme]);
  return <WtsCalendarReact
    initialOptions={{ ...appearance, view: 'month' }}
    options={appearance}
    events={[]}
  />;
}
Adapter signature →

shadcn/ui

Mount under your existing semantic-variable theme scope. Complete CSS colors are the default (including OKLCH); older bare HSL channels need colorFormat: 'hsl'. Changing an ancestor's .dark class updates inherited colors without rebuilding events.

shadcn/ui / React
'use client';
import { WtsCalendarReact } from '@wts-calendar/react';
import { createShadcnCalendarTheme } from '@wts-calendar/core/theme-shadcn';
import '@wts-calendar/core/styles/calendar.css';

const appearance = createShadcnCalendarTheme();
// Older themes with bare HSL channels: { colorFormat: 'hsl' }
export function Calendar() {
  return <WtsCalendarReact
    initialOptions={{ ...appearance, view: 'month' }}
    events={[]}
  />;
}
Adapter signature →

Angular Material

The Material 3 adapter uses Angular Material 19+ --mat-sys-* system tokens generated by mat.theme(). Keep the theme in global Sass and the calendar underneath its scope.

Global Material theme
// Keep calendar.css in the application's global styles list.
@use '@angular/material' as mat;
html {
  color-scheme: light dark;
  @include mat.theme((
    color: mat.$violet-palette,
    typography: Roboto,
    density: 0,
  ));
}
html.light-mode { color-scheme: light; }
html.dark-mode { color-scheme: dark; }
Angular wrapper
import { Component } from '@angular/core';
import { WtsCalendarAngularComponent } from '@wts-calendar/angular';
import { createAngularMaterialCalendarTheme } from '@wts-calendar/core/theme-angular-material';

@Component({
  selector: 'app-calendar',
  standalone: true,
  imports: [WtsCalendarAngularComponent],
  template: '<wts-calendar-angular [initialOptions]="options" />',
})
export class CalendarComponent {
  readonly options = {
    ...createAngularMaterialCalendarTheme(),
    view: 'month' as const,
  };
}

The app's CSS color-scheme controls light/dark mode. Changing only WTS colorScheme does not switch Material's palette. Density, ripples, component templates, and Material 2 conversion are not provided. Older themes need explicit WTS themeTokens; light-dark() requires browser support.

Adapter signature →
Open the existing appearance example →