Skip to content

@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-calendar
css
@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 ClassDescription
.calendarRoot container — view mode, slot interval, compact toggle
.calendar-headerTop bar — navigation + title + view switcher
.calendar-header-titleTitle text in the header
.calendar-header-navNavigation button group
.calendar-header-actionsAction button group
.calendar-time-gridScrollable grid container for day/week views
.calendar-column-headersFixed column header row
.calendar-time-gutterLeft column with hour labels
.calendar-time-gutter-labelIndividual hour label
.calendar-day-columnSingle day lane
.calendar-day-column-headerDay name + date header
.calendar-day-column-header-dateDate number
.calendar-day-column-header-dayDay name
.calendar-time-slotTime cell
.calendar-all-day-rowAll-day events strip
.calendar-all-day-label"All day" gutter label
.calendar-all-day-cellAll-day events container per day
.calendar-eventTimed event block
.calendar-event-titleEvent title
.calendar-event-timeEvent time
.calendar-event-indicatorColour dot
.calendar-event-resize-handleBottom resize handle
.calendar-now-indicatorCurrent time line
.calendar-month-gridMonth view grid (7 columns)
.calendar-month-weekday-headerWeekday name
.calendar-week-numberWeek number cell
.calendar-month-cellDay cell in month view
.calendar-month-cell-headerDay number
.calendar-month-cell-eventsEvents container
.calendar-month-eventCompact event row
.calendar-more"+N more" indicator
.calendar-multi-day-barMulti-day bar
.calendar-year-gridYear view grid (4 columns)
.calendar-year-monthMini month in year view
.calendar-year-month-headerMonth name
.calendar-year-month-gridMini day grid
.calendar-year-weekdayWeekday initial
.calendar-year-dayDay cell in year view

Tokens (calendar.css)

All tokens are in @layer kapish.tokens on :root. Prefix: --calendar-*.

Layout

TokenDefault
--calendar-min-height36rem
--calendar-bordervar(--border-default)
--calendar-radiusvar(--radius-lg, 0.5rem)
--calendar-bgvar(--surface-base)
TokenDefault
--calendar-header-height3rem
--calendar-header-bgvar(--surface-elevated)
--calendar-header-bordervar(--border-default)
--calendar-header-font-sizevar(--text-md, 1rem)
--calendar-header-font-weight600

Time Gutter

TokenDefault
--calendar-gutter-width4rem
--calendar-gutter-bgvar(--surface-elevated)
--calendar-gutter-bordervar(--border-default)
--calendar-gutter-font-sizevar(--font-size-xs, 0.75rem)
--calendar-gutter-colorvar(--text-secondary)

Day Column

TokenDefault
--calendar-day-column-bordervar(--border-subtle)
--calendar-day-column-today-bgaccent alpha 5%
--calendar-day-column-weekend-bgvar(--surface-sunken)
--calendar-day-column-selected-bgaccent alpha 10%

Time Slots

TokenDefault
--calendar-slot-height-604rem
--calendar-slot-height-302rem
--calendar-slot-height-151rem
--calendar-slot-bordervar(--border-subtle)
--calendar-slot-half-bordervar(--border-faint, rgba(255, 255, 255, 0.25))
--calendar-slot-quarter-bordervar(--border-faint, rgba(255, 255, 255, 0.20))
--calendar-slot-hover-bgaccent alpha 5%
--calendar-slot-outside-working-hours-bgrgba(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.

VariantBackground hue
accentAccent colour
successGreen 600
warningAmber 600
dangerRed 600
infoCyan 600
neutralNeutral 600

Event State

TokenDefault
--calendar-event-selected-ring-width2px
--calendar-event-selected-ringvar(--color-accent)
--calendar-event-dragging-opacity0.7
--calendar-event-dragging-shadow0 4px 12px rgba(0,0,0,0.3)

Now Indicator

TokenDefault
--calendar-now-colorvar(--color-danger, #ef4444)
--calendar-now-width2px
--calendar-now-dot-size0.5rem

Variants

Calendar root

data-viewday · week · month · yeardata-slot-interval15 · 30 · 60

Event

data-variantaccent · success · warning · danger · info · neutraldata-sizesm · md · lg

Multi-Day Bar / Month Event

data-variantaccent · 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

FileContents
calendar.cssToken definitions (@layer kapish.tokens)
calendar.g.cssGenerated component rules (@layer kapish.components)
index.cssBarrel importing both CSS files
index.js + index.d.tsCompiled TypeScript types

Build

bash
npm run build

Usage 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

AttributeValuesNotes
data-viewday week month yearView mode
data-slot-interval15 30 60Time slot granularity
data-compactboolean flagReduces slot and cell heights
data-show-week-numbersboolean flagAdds week number column to month grid

Event

AttributeValuesNotes
data-variantaccent success warning danger info neutralColour scheme
data-sizesm md lgFont size
data-all-dayboolean flagSwitches to static positioning
data-selectedboolean flagAccent ring
data-draggingboolean flagDrag state
data-resizingboolean flagResize state
data-interactiveboolean flagPointer cursor + hover
data-continuedboolean flagLeft edge clipped (continues from previous day)
data-continuesboolean flagRight edge clipped (continues into next day)
data-coloredboolean flagUses --calendar-event-color custom property

Month Cell

AttributeValuesNotes
data-todayboolean flagToday highlight
data-outsideboolean flagOutside current month
data-weekendboolean flagWeekend background
data-selectedboolean flagSelected highlight
data-disabledboolean flagDimmed + 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">&lsaquo;</button>
      <button class="btn" data-variant="ghost" data-size="sm">&rsaquo;</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>

Carrot