Styling and theming
Month-view week rows fill the available calendar height by default. Set height (for example,
height="800px" or height="100%" inside a parent with a defined height) to size the calendar.
Without a defined height, rows size naturally to their content. Crowded weeks can grow to show
all events; use dayMaxEvents: true for uniform rows with overflow behind a “+N more” link.
The stylesheet ships as z-cal/style.css (also bundled as z-cal.global.css next to the
IIFE build). Import it explicitly when consuming the published package. The polyfill import can be
omitted when every target runtime has native Temporal. The CDN bundle includes the polyfill and
exposes plugins directly, for example ZCal.DayGrid.
Every rule lives in a cascade layer named z-cal, so any unlayered rule you write wins over the
library's regardless of selector specificity:
Tailwind v4
Declare the complete layer order before either stylesheet is loaded. Put the calendar after Tailwind's base reset and before your component/utility overrides:
Use this in your global CSS entry, then import that entry from the application. Keep the same ordering in separate editor, preview, or embedded-document entries. Avoid separately importing the calendar CSS before this declaration: the first declaration establishes layer precedence.
Tailwind Preflight lives in base and resets borders.
If z-cal is established before base, reset rules can erase calendar borders and CSS-drawn
navigation arrows. The order above lets calendar styles restore them while retaining utility
overrides. Unlayered application CSS still takes precedence over normal layered rules.
Tokens
The design is driven by a handful of custom properties on .cx. Override them on .cx (or any
selector that matches the calendar root):
These are derived from the primary tokens with color-mix() and can be overridden individually:
Time-grid and resource time-grid views can fill a constrained calendar height with
expandRows: true. slotHeight stays the minimum;
use the option so the rendered rows and time geometry remain aligned.
Layout properties written by the views (--cx-slot-height, --cx-slot-width, --cx-sidebar-width,
--cx-grid-cols, …) are internal; drive them through options such as slotHeight and slotWidth.
Dark mode
Colours are defined with light-dark(), so the calendar follows the color-scheme of the page. Set
color-scheme: dark (or light dark) on html and the calendar switches with it.
To pin the calendar independently of the page, use the colorScheme option ('light', 'dark' or
the default 'auto'):
The option adds cx-light / cx-dark to the root; the same classes work on any ancestor
(<body class="cx-dark">) because they only set color-scheme.
Business hours
Time outside businessHours is painted by an overlay inside each
day cell, above its background and grid lines and below its content. Time grids and timelines mask
the overlay to the closed slots; day grids, the all-day row, and month timelines show it over whole
closed days, which also carry the nonBusiness class (cx-non-business). The overlay's
background is --cx-non-business-bg, so it takes anything a background does: a colour, a
color-mix() of your own tokens, or a gradient pattern. It mixes from --cx-text by default, so
it follows dark mode on its own.
Set the token on .cx, any ancestor, or a class of your own on the root; with Tailwind, a rule in
components (or unlayered CSS) wins over the z-cal layer. To style whole closed days differently
from closed slots, target the class:
Remap the class through theme: { nonBusiness: 'closed' } when your design system owns the name.
The mask and display of the overlay (--cx-non-business-mask, --cx-non-business-display) are
written by the views and are internal, like the other layout properties.
Event colours
coloris an accent: the stylesheet derives a soft tint (pale background, coloured text and border in light mode; a deeper tint with light text in dark mode) and the small dot in front of the title. Consumer colours therefore adapt to both schemes.backgroundColorandtextColorare used verbatim (the event getscx-event-solid).- The calendar-wide defaults are
eventColor,eventBackgroundColorandeventTextColor; resources may seteventBackgroundColor/eventTextColor.
The resolved values reach the element as --cx-event-accent, --cx-event-bg and --cx-event-text,
so a stylesheet can restyle them too. For example, to render every event as a solid fill:
Hide the accent dot with --cx-event-dot: none (the demo uses this for plain event text).
Class names
Every class the renderer emits is listed in the theme option and can be remapped or extended:
React passes the same option through its theme prop. Retain the original class when you want
to extend rather than replace built-in styling. nonBusiness marks day cells whose whole date is
outside business hours. keyboardCursor styles the focused-slot marker of
keyboard navigation and liveRegion its
visually hidden announcer; the root carries data-cx-keyboard while a day cell has focus, and
--cx-focus-ring colours both the cell outline and the cursor.
Event attributes
eventAttrs adds attributes to every event element, statically or per event, so application
state such as a selected event reaches the DOM without imperative element access:
true sets an empty attribute, false, null, and undefined remove it, and attributes the
function stops returning are removed on the next render. The element's own role, tabindex,
and data-cx-event cannot be overridden. Pass a new function (or object) when the state it reads
changes; React props do this naturally.
Custom content and icons
Use React content slots for JSX. In vanilla code, eventContent
accepts text or { domNodes: Node[] }. Explicit { html: string } content is trusted HTML; sanitize
untrusted markup before supplying it. Plain strings are rendered as text. Adding a renderer replaces
the event body, so include its time and title when you want to retain them.