Appearance
@carrot/design-components-calendar
Framework-agnostic CSS and TypeScript types for calendar views: day, week, month, and year layouts with timed events, all-day events, recurring series, custom colours, drag/resize states, and now-indicator.
Installation
bash
npm install @carrot/design-components-calendarcss
@import "@carrot/design-components-calendar";ts
import type { CalendarEventVariant, CalendarView } from "@carrot/design-components-calendar/types";
import { CalendarViews, CalendarEventVariants } from "@carrot/design-components-calendar/types";Contents
Sub-Components
| Base Class | Description |
|---|---|
.calendar | Root container — view mode, slot interval, compact toggle |
.calendar-header | Top bar — navigation + title + view switcher |
.calendar-header-title | Title text in the header |
.calendar-header-nav | Navigation button group |
.calendar-header-actions | Action button group |
.calendar-time-grid | Scrollable grid container for day/week views |
.calendar-column-headers | Fixed column header row |
.calendar-time-gutter | Left column with hour labels |
.calendar-time-gutter-label | Individual hour label |
.calendar-day-column | Single day lane |
.calendar-day-column-header | Day name + date header |
.calendar-day-column-header-date | Date number |
.calendar-day-column-header-day | Day name |
.calendar-time-slot | Time cell |
.calendar-all-day-row | All-day events strip |
.calendar-all-day-label | "All day" gutter label |
.calendar-all-day-cell | All-day events container per day |
.calendar-event | Timed event block |
.calendar-event-title | Event title |
.calendar-event-time | Event time |
.calendar-event-indicator | Colour dot |
.calendar-event-resize-handle | Bottom resize handle |
.calendar-now-indicator | Current time line |
.calendar-month-grid | Month view grid (7 columns) |
.calendar-month-weekday-header | Weekday name |
.calendar-week-number | Week number cell |
.calendar-month-cell | Day cell in month view |
.calendar-month-cell-header | Day number |
.calendar-month-cell-events | Events container |
.calendar-month-event | Compact event row |
.calendar-more | "+N more" indicator |
.calendar-multi-day-bar | Multi-day bar |
.calendar-year-grid | Year view grid (4 columns) |
.calendar-year-month | Mini month in year view |
.calendar-year-month-header | Month name |
.calendar-year-month-grid | Mini day grid |
.calendar-year-weekday | Weekday initial |
.calendar-year-day | Day cell in year view |
Tokens (calendar.css)
All tokens are in @layer kapish.tokens on :root. Prefix: --calendar-*.
Layout
| Token | Default |
|---|---|
--calendar-min-height | 36rem |
--calendar-border | var(--border-default) |
--calendar-radius | var(--radius-lg, 0.5rem) |
--calendar-bg | var(--surface-base) |
Header
| Token | Default |
|---|---|
--calendar-header-height | 3rem |
--calendar-header-bg | var(--surface-elevated) |
--calendar-header-border | var(--border-default) |
--calendar-header-font-size | var(--text-md, 1rem) |
--calendar-header-font-weight | 600 |
Time Gutter
| Token | Default |
|---|---|
--calendar-gutter-width | 4rem |
--calendar-gutter-bg | var(--surface-elevated) |
--calendar-gutter-border | var(--border-default) |
--calendar-gutter-font-size | var(--font-size-xs, 0.75rem) |
--calendar-gutter-color | var(--text-secondary) |
Day Column
| Token | Default |
|---|---|
--calendar-day-column-border | var(--border-subtle) |
--calendar-day-column-today-bg | accent alpha 5% |
--calendar-day-column-weekend-bg | var(--surface-sunken) |
--calendar-day-column-selected-bg | accent alpha 10% |
Time Slots
| Token | Default |
|---|---|
--calendar-slot-height-60 | 4rem |
--calendar-slot-height-30 | 2rem |
--calendar-slot-height-15 | 1rem |
--calendar-slot-border | var(--border-subtle) |
--calendar-slot-half-border | var(--border-faint, rgba(255, 255, 255, 0.25)) |
--calendar-slot-quarter-border | var(--border-faint, rgba(255, 255, 255, 0.20)) |
--calendar-slot-hover-bg | accent alpha 5% |
--calendar-slot-outside-working-hours-bg | rgba(0, 0, 0, 0.35) |
Event Colours
Each event variant has three tokens: --calendar-event-{variant}-bg, --calendar-event-{variant}-fg, --calendar-event-{variant}-border.
| Variant | Background hue |
|---|---|
accent | Accent colour |
success | Green 600 |
warning | Amber 600 |
danger | Red 600 |
info | Cyan 600 |
neutral | Neutral 600 |
Event State
| Token | Default |
|---|---|
--calendar-event-selected-ring-width | 2px |
--calendar-event-selected-ring | var(--color-accent) |
--calendar-event-dragging-opacity | 0.7 |
--calendar-event-dragging-shadow | 0 4px 12px rgba(0,0,0,0.3) |
Now Indicator
| Token | Default |
|---|---|
--calendar-now-color | var(--color-danger, #ef4444) |
--calendar-now-width | 2px |
--calendar-now-dot-size | 0.5rem |
Variants
Calendar root
data-view — day · week · month · yeardata-slot-interval — 15 · 30 · 60
Event
data-variant — accent · success · warning · danger · info · neutraldata-size — sm · md · lg
Multi-Day Bar / Month Event
data-variant — accent · success · warning · danger · info · neutral
Boolean Flags
Calendar: data-compact · data-show-week-numbers Day column: data-today · data-weekend · data-selected Time slot: data-half-hour · data-minor · data-micro · data-outside-working-hours All-day row: data-collapsed Event: data-all-day · data-selected · data-dragging · data-resizing · data-interactive · data-continued · data-continues · data-colored Month cell: data-today · data-selected · data-outside · data-weekend · data-disabled Month event: data-all-day · data-multi-day · data-continued · data-continues · data-colored More: data-interactive Multi-day bar: data-continued · data-continues · data-selected · data-colored Year month: data-current Year day: data-today · data-outside · data-weekend · data-has-events
TypeScript Exports
Const arrays: CalendarViews · CalendarEventVariants · CalendarEventSizes · CalendarSlotIntervals · CalendarWeekStarts · CalendarWorkingHoursModes Types: CalendarView · CalendarEventVariant · CalendarEventSize · CalendarSlotInterval · CalendarWeekStart · CalendarWorkingHoursMode Style props: CalendarStyleProps · CalendarHeaderStyleProps · CalendarTimeGutterStyleProps · CalendarDayColumnStyleProps · CalendarDayColumnHeaderStyleProps · CalendarTimeSlotStyleProps · CalendarAllDayRowStyleProps · CalendarEventStyleProps · CalendarEventTitleStyleProps · CalendarEventTimeStyleProps · CalendarNowIndicatorStyleProps · CalendarMonthCellStyleProps · CalendarMonthCellHeaderStyleProps · CalendarMonthEventStyleProps · CalendarMoreStyleProps · CalendarMultiDayBarStyleProps · CalendarYearMonthStyleProps · CalendarYearDayStyleProps
Dist Structure
| File | Contents |
|---|---|
calendar.css | Token definitions (@layer kapish.tokens) |
calendar.g.css | Generated component rules (@layer kapish.components) |
index.css | Barrel importing both CSS files |
index.js + index.d.ts | Compiled TypeScript types |
Build
bash
npm run buildUsage Guide
Included in the umbrella. If you already import
@carrot/design-components, calendar CSS and types are available automatically — no extra install needed.
Import
css
/* Already included in the umbrella: */
@import "@carrot/design-components";
/* Or import individually: */
@import "@carrot/design-components-calendar";ts
// Types from the umbrella:
import type { CalendarStyleProps, CalendarEventStyleProps } from "@carrot/design-components/types";
// Or from the individual package:
import { CalendarEventVariants, CalendarViews } from "@carrot/design-components-calendar/types";
import type { CalendarStyleProps, CalendarEventStyleProps } from "@carrot/design-components-calendar/types";Variants
Calendar root
| Attribute | Values | Notes |
|---|---|---|
data-view | day week month year | View mode |
data-slot-interval | 15 30 60 | Time slot granularity |
data-compact | boolean flag | Reduces slot and cell heights |
data-show-week-numbers | boolean flag | Adds week number column to month grid |
Event
| Attribute | Values | Notes |
|---|---|---|
data-variant | accent success warning danger info neutral | Colour scheme |
data-size | sm md lg | Font size |
data-all-day | boolean flag | Switches to static positioning |
data-selected | boolean flag | Accent ring |
data-dragging | boolean flag | Drag state |
data-resizing | boolean flag | Resize state |
data-interactive | boolean flag | Pointer cursor + hover |
data-continued | boolean flag | Left edge clipped (continues from previous day) |
data-continues | boolean flag | Right edge clipped (continues into next day) |
data-colored | boolean flag | Uses --calendar-event-color custom property |
Month Cell
| Attribute | Values | Notes |
|---|---|---|
data-today | boolean flag | Today highlight |
data-outside | boolean flag | Outside current month |
data-weekend | boolean flag | Weekend background |
data-selected | boolean flag | Selected highlight |
data-disabled | boolean flag | Dimmed + no pointer events |
Event position and height are set via top, height, left, and width inline styles.
Examples
Day view with timed events
html
<div class="calendar" data-view="day" data-slot-interval="60">
<div class="calendar-header">
<div class="calendar-header-nav">
<button class="btn" data-variant="ghost" data-size="sm">‹</button>
<button class="btn" data-variant="ghost" data-size="sm">›</button>
<button class="btn" data-variant="ghost" data-size="sm">Today</button>
</div>
<div class="calendar-header-title">Mon 23 March 2026</div>
<div class="calendar-header-actions"></div>
</div>
<div class="calendar-column-headers" style="--calendar-visible-days: 1">
<div class="calendar-day-column-header" style="grid-column: 1"></div>
<div class="calendar-day-column-header" data-today>
<span class="calendar-day-column-header-date">23</span>
</div>
</div>
<div class="calendar-time-grid" style="--calendar-visible-days: 1">
<div class="calendar-time-gutter">
<span class="calendar-time-gutter-label" style="top: 0px">00:00</span>
<span class="calendar-time-gutter-label" style="top: 64px">01:00</span>
<!-- ... -->
</div>
<div class="calendar-day-column" data-today>
<div class="calendar-time-slot" style="height: 64px"></div>
<div class="calendar-time-slot" style="height: 64px"></div>
<!-- ... 24 slots -->
<!-- Timed event: 09:00 - 10:30 -->
<div class="calendar-event" data-variant="accent" data-size="md" data-interactive
style="top: 576px; height: 96px; left: 0; width: 100%;">
<span class="calendar-event-title">Team standup</span>
<span class="calendar-event-time">09:00</span>
<div class="calendar-event-resize-handle"></div>
</div>
<div class="calendar-now-indicator" style="top: 640px"></div>
</div>
</div>
</div>Month view with mixed events
html
<div class="calendar" data-view="month">
<div class="calendar-header"><!-- ... --></div>
<div class="calendar-month-grid">
<div class="calendar-month-weekday-header">Mon</div>
<div class="calendar-month-weekday-header">Tue</div>
<!-- ... 5 more -->
<div class="calendar-month-cell" data-today>
<div class="calendar-month-cell-header" data-today>22</div>
<div class="calendar-month-cell-events">
<div class="calendar-month-event" data-variant="accent" data-all-day>Sprint review</div>
<div class="calendar-month-event">
<span class="calendar-event-indicator"></span>
14:00 1:1 with Alice
</div>
<div class="calendar-more" data-interactive>+3 more</div>
</div>
</div>
<div class="calendar-month-cell" data-weekend>
<div class="calendar-month-cell-header">23</div>
<div class="calendar-month-cell-events"></div>
</div>
</div>
</div>Custom-coloured event
html
<div class="calendar-event" data-colored data-interactive data-size="md"
style="--calendar-event-color: #8b5cf6; --calendar-event-color-fg: #fff;
top: 384px; height: 64px;">
<span class="calendar-event-title">Custom purple event</span>
<span class="calendar-event-time">06:00</span>
</div>Multi-day event spanning across month cells
html
<!-- Day 1: starts here -->
<div class="calendar-month-event" data-variant="success" data-all-day data-continues>
Holiday
</div>
<!-- Day 2: middle -->
<div class="calendar-month-event" data-variant="success" data-all-day data-continued data-continues>
Holiday
</div>
<!-- Day 3: ends here -->
<div class="calendar-month-event" data-variant="success" data-all-day data-continued>
Holiday
</div>Working hours dim mode
Non-working time slots receive data-outside-working-hours for a dark overlay:
html
<div class="calendar" data-view="day" data-slot-interval="30">
<!-- ... header ... -->
<div class="calendar-time-grid" style="--calendar-visible-days: 1">
<div class="calendar-time-gutter"><!-- labels --></div>
<div class="calendar-day-column">
<!-- Before working hours — dimmed -->
<div class="calendar-time-slot" data-outside-working-hours style="height: 32px"></div>
<div class="calendar-time-slot" data-outside-working-hours data-minor style="height: 32px"></div>
<!-- ... -->
<!-- Working hours — normal -->
<div class="calendar-time-slot" style="height: 32px"></div>
<div class="calendar-time-slot" data-minor style="height: 32px"></div>
<!-- ... -->
</div>
</div>
</div>Grid line tiers (15-minute slots)
With data-slot-interval="15", each hour has four slots with progressively subtler grid lines:
html
<div class="calendar-time-slot" style="height: 16px"></div> <!-- :00 — solid -->
<div class="calendar-time-slot" data-micro style="height: 16px"></div> <!-- :15 — dotted -->
<div class="calendar-time-slot" data-minor style="height: 16px"></div> <!-- :30 — dashed -->
<div class="calendar-time-slot" data-micro style="height: 16px"></div> <!-- :45 — dotted -->Year view with event dots
html
<div class="calendar" data-view="year">
<div class="calendar-header"><!-- ... --></div>
<div class="calendar-year-grid">
<div class="calendar-year-month" data-current>
<div class="calendar-year-month-header">Mar</div>
<div class="calendar-year-month-grid">
<span class="calendar-year-weekday">M</span>
<!-- ... 6 more -->
<span class="calendar-year-day" data-today data-has-events>22</span>
<span class="calendar-year-day" data-weekend>23</span>
</div>
</div>
<!-- ... 11 more months -->
</div>
</div>