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-part | Component | Attributes |
|---|---|---|
day-grid-section | DayGridViewSection | data-month, data-resource-id |
day-grid-section-header | DayGridViewSectionHeader | |
day-grid-root | DayGridView | data-multi-month |
day-grid-header | DayGridViewHeader | |
day-grid-header-cell | DayGridViewHeaderCell | data-weekday (1 to 7), data-resource-id |
day-grid-row | DayGridViewRow | |
day-grid-day | DayGridViewDay | data-today, data-outside, data-date, data-weekday, data-resource-id |
day-grid-day-trigger | DayGridViewDayTrigger | |
day-grid-row-event | DayGridViewRowEvent | data-all-day, data-multi-day, data-continues-before, data-continues-after |
day-grid-row-background-event | DayGridViewRowBackgroundEvent | data-continues-before, data-continues-after |
day-grid-day-background | DayGridViewDayBackground | data-layer, data-kind |
day-grid-overflow | DayGridViewOverflow | data-hidden-count |
Time grid
data-part | Component | Attributes |
|---|---|---|
time-grid-root | TimeGridView | |
time-grid-header | TimeGridViewHeader | |
time-grid-column-header | TimeGridViewColumnHeader | data-today, data-weekday, data-unavailable, data-resource-id |
time-grid-column-trigger | TimeGridViewColumnTrigger | |
time-grid-all-day | TimeGridViewAllDay | |
time-grid-all-day-event | TimeGridViewAllDayEvent | data-all-day, data-multi-day, data-continues-before, data-continues-after |
time-grid-all-day-background-event | TimeGridViewAllDayBackgroundEvent | data-continues-before, data-continues-after |
time-grid-body | TimeGridViewBody | |
time-grid-axis | TimeGridViewAxis | |
time-grid-axis-label | TimeGridViewAxisLabel | data-day-offset |
time-grid-column | TimeGridViewColumn | data-today, data-weekday, data-unavailable |
time-grid-unavailable | TimeGridViewUnavailable | |
time-grid-background | TimeGridViewBackground | data-layer, data-kind |
time-grid-background-event | TimeGridViewBackgroundEvent | data-continues-before, data-continues-after |
time-grid-event | TimeGridViewEvent | data-overlap, data-short, data-continues-before, data-continues-after |
time-grid-now | TimeGridViewNowIndicator |
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-part | Component | Attributes |
|---|---|---|
timeline-root | TimelineView | |
timeline-header | TimelineViewHeader | |
timeline-day-header | TimelineViewDayHeader | data-today, data-date, data-weekday |
timeline-day-trigger | TimelineViewDayTrigger | |
timeline-slot-label | TimelineViewSlotLabel | data-day-offset |
timeline-body | TimelineViewBody | |
timeline-row | TimelineViewRow | data-unavailable, data-resource-id |
timeline-resource | TimelineViewResource | data-unavailable, data-resource-id |
timeline-lane | TimelineViewLane | data-unavailable |
timeline-unavailable | TimelineViewUnavailable | |
timeline-background | TimelineViewBackground | data-layer, data-kind |
timeline-background-event | TimelineViewBackgroundEvent | data-continues-before, data-continues-after |
timeline-event | TimelineViewEvent | data-all-day, data-multi-day, data-continues-before, data-continues-after |
timeline-now | TimelineViewNowIndicator |
List
data-part | Component | Attributes |
|---|---|---|
list-root | ListView | |
list-section | ListViewSection | data-date, data-resource-id |
list-section-header | ListViewSectionHeader | |
list-day | ListViewDay | data-date, data-resource-id |
list-day-header | ListViewDayHeader | |
list-event | ListViewEvent | |
list-empty | ListViewEmpty |
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.
| Part | Variables |
|---|---|
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));
}