calendar-tsx

Custom themes

Write your own look on top of base.css, using the parts' attributes and geometry.

base.css positions everything: day-grid bars, time-grid columns and lanes, timeline rows and the now line. A custom theme imports it and adds only the look. To try token values first, use the playground: its token editor overrides the color and size tokens of any built-in theme and checks the contrast of the result.

@import '@calendar-tsx/themes/base.css';

@layer calendar.theme {
  :where([data-scope='calendar'][data-part='time-grid-event']) {
    background: var(--brand-event);
    border-radius: 4px;
  }
}

Writing into calendar.theme puts your rules where a built-in theme's go, so compact.css and unlayered overrides still apply on top. Use :where() to keep specificity at zero. The size tokens (--calendar-slot-height, --calendar-bar-height, --calendar-axis-width and the rest) also drive positioning in base.css; see tokens.

Keep inline padding and borders inside a timeline event's box. The core sizes and stacks events from their display duration, so CSS that widens a bar would draw it over its neighbors.

Parts

Every part renders data-scope='calendar' and one data-part. Boolean state attributes are present (data-x="") when true and absent otherwise.

Day grid

data-partComponentAttributes
day-grid-sectionDayGridViewSectiondata-month, data-resource-id
day-grid-section-headerDayGridViewSectionHeader
day-grid-rootDayGridViewdata-multi-month
day-grid-headerDayGridViewHeader
day-grid-header-cellDayGridViewHeaderCelldata-weekday (1 to 7), data-resource-id
day-grid-rowDayGridViewRow
day-grid-dayDayGridViewDaydata-today, data-outside, data-date, data-weekday, data-resource-id
day-grid-day-triggerDayGridViewDayTrigger
day-grid-row-eventDayGridViewRowEventdata-all-day, data-multi-day, data-continues-before, data-continues-after
day-grid-row-background-eventDayGridViewRowBackgroundEventdata-continues-before, data-continues-after
day-grid-day-backgroundDayGridViewDayBackgrounddata-layer, data-kind
day-grid-overflowDayGridViewOverflowdata-hidden-count

Time grid

data-partComponentAttributes
time-grid-rootTimeGridView
time-grid-headerTimeGridViewHeader
time-grid-column-headerTimeGridViewColumnHeaderdata-today, data-weekday, data-unavailable, data-resource-id
time-grid-column-triggerTimeGridViewColumnTrigger
time-grid-all-dayTimeGridViewAllDay
time-grid-all-day-eventTimeGridViewAllDayEventdata-all-day, data-multi-day, data-continues-before, data-continues-after
time-grid-all-day-background-eventTimeGridViewAllDayBackgroundEventdata-continues-before, data-continues-after
time-grid-bodyTimeGridViewBody
time-grid-axisTimeGridViewAxis
time-grid-axis-labelTimeGridViewAxisLabeldata-day-offset
time-grid-columnTimeGridViewColumndata-today, data-weekday, data-unavailable
time-grid-unavailableTimeGridViewUnavailable
time-grid-backgroundTimeGridViewBackgrounddata-layer, data-kind
time-grid-background-eventTimeGridViewBackgroundEventdata-continues-before, data-continues-after
time-grid-eventTimeGridViewEventdata-overlap, data-short, data-continues-before, data-continues-after
time-grid-nowTimeGridViewNowIndicator

data-overlap marks an event whose overlap cluster needs more than one lane. data-short marks an event laid out shorter than the view's shortEventMinutes. data-all-day marks an all-day event's bar and data-multi-day one whose event covers more than one date, before clipping; a timed event ending at midnight covers only its start date. data-weekday is the ISO day of the week, 1 (Monday) to 7 (Sunday). data-day-offset is the number of days a slot starts after its date, for labelling after-midnight times in an overnight timeWindow.

Timeline

data-partComponentAttributes
timeline-rootTimelineView
timeline-headerTimelineViewHeader
timeline-day-headerTimelineViewDayHeaderdata-today, data-date, data-weekday
timeline-day-triggerTimelineViewDayTrigger
timeline-slot-labelTimelineViewSlotLabeldata-day-offset
timeline-bodyTimelineViewBody
timeline-rowTimelineViewRowdata-unavailable, data-resource-id
timeline-resourceTimelineViewResourcedata-unavailable, data-resource-id
timeline-laneTimelineViewLanedata-unavailable
timeline-unavailableTimelineViewUnavailable
timeline-backgroundTimelineViewBackgrounddata-layer, data-kind
timeline-background-eventTimelineViewBackgroundEventdata-continues-before, data-continues-after
timeline-eventTimelineViewEventdata-all-day, data-multi-day, data-continues-before, data-continues-after
timeline-nowTimelineViewNowIndicator

List

data-partComponentAttributes
list-rootListView
list-sectionListViewSectiondata-date, data-resource-id
list-section-headerListViewSectionHeader
list-dayListViewDaydata-date, data-resource-id
list-day-headerListViewDayHeader
list-eventListViewEvent
list-emptyListViewEmpty

Geometry

Parts emit their layout as unitless --cal-* custom properties on their own element, which base.css reads. --cal-slot-units is the visible duration in slots and can end in a partial slot, where --cal-slots counts whole slot labels.

PartVariables
day-grid-root--cal-month-rows: the largest section row count, for aligning month overview panels
day-grid-section--cal-columns
day-grid-row--cal-rows: bar rows shown; --cal-columns
day-grid-row-event, time-grid-all-day-event--cal-col-start, --cal-col-span, --cal-row (zero-based)
day-grid-row-background-event, time-grid-all-day-background-event--cal-col-start, --cal-col-span
time-grid-root--cal-columns, --cal-slots, --cal-slot-units, --cal-all-day-rows, --cal-min-column-width, --cal-slots-per-hour, --cal-hour-offset: slots before the first hour
time-grid-body--cal-slots, --cal-slot-units, --cal-slots-per-hour, --cal-hour-offset
time-grid-axis-label--cal-start, --cal-span (fractions of the window)
time-grid-column--cal-column-lanes: the most lanes in the column
time-grid-event--cal-start, --cal-span (fractions of the day), --cal-lane, --cal-lanes, --cal-inline-start, --cal-inline-size (fractions of the width)
time-grid-unavailable, time-grid-background, time-grid-background-event--cal-start, --cal-span
time-grid-now--cal-now (fraction of the day)
timeline-root--cal-slots, --cal-slot-units, --cal-days, --cal-day-slot-units, --cal-slot-columns (a grid track list sized by each slot's span), --cal-min-slot-width, --cal-slots-per-hour, --cal-hour-offset
timeline-day-header--cal-col-start, --cal-col-span (slot columns)
timeline-slot-label--cal-col-start
timeline-row--cal-rows: stack depth
timeline-event--cal-start, --cal-span (fractions of the range), --cal-row
timeline-unavailable, timeline-background, timeline-background-event--cal-start, --cal-span
timeline-now--cal-now (fraction of the range)
list-day--cal-events: event rows spanned by the date heading

For example, base.css places a timed event with:

:where([data-scope='calendar'][data-part='time-grid-event']) {
  position: absolute;
  inset-block-start: calc(var(--cal-start) * 100%);
  block-size: calc(var(--cal-span) * 100% - var(--calendar-event-gap, 4px));
  inset-inline-start: calc(var(--cal-inline-start) * 100%);
  inline-size: calc(var(--cal-inline-size) * 100% - var(--calendar-event-gap, 4px));
  z-index: calc(1 + var(--cal-lane));
}