Skip to content

myalim/chronoview

Repository files navigation

ChronoView

npm license TypeScript

Headless timeline library for React.

One data model, multiple views — Schedule, Calendar, Grid across Day, Week, and Month.

Features

  • Headless core + ready-to-use UI — Use pre-built components or build your own with hooks
  • Multiple views — Schedule (resource × time), Calendar, Grid × Day/Week/Month
  • Large datasets — Virtual scrolling for 10,000+ events at 60fps
  • Customizable — CSS variables for theming, dark mode, custom renderers
  • TypeScript — Fully typed API
  • MIT licensed — Free for commercial use

Packages

Package Description
@chronoview/core Framework-agnostic core engine (time calculations, layout, stacking)
@chronoview/react React hooks and context (headless)
@chronoview/ui Pre-built UI components with design tokens

Quick Start

Install

npm install @chronoview/ui
Other package managers
pnpm add @chronoview/ui
yarn add @chronoview/ui
bun add @chronoview/ui

@chronoview/ui includes @chronoview/core and @chronoview/react as dependencies.

Peer dependencies: react >= 18, react-dom >= 18, @floating-ui/react >= 0.27

Setup CSS

Import the stylesheet in your app's entry CSS file or root component:

@import "@chronoview/ui/styles.css";

This single file includes all design tokens and component styles. No Tailwind CSS required in your project.

Basic Usage

import { Schedule } from "@chronoview/ui";
import type { Resource, TimelineEvent } from "@chronoview/core";

const resources: Resource[] = [
  { id: "room-1", title: "Meeting Room A", color: "#3b82f6" },
  { id: "room-2", title: "Meeting Room B", color: "#8b5cf6" },
];

const events: TimelineEvent[] = [
  {
    id: "evt-1",
    resourceId: "room-1",
    start: new Date(2026, 2, 29, 9, 0),
    end: new Date(2026, 2, 29, 10, 30),
    title: "Team Standup",
  },
  {
    id: "evt-2",
    resourceId: "room-1",
    start: new Date(2026, 2, 29, 14, 0),
    end: new Date(2026, 2, 29, 15, 30),
    title: "Client Meeting",
  },
  {
    id: "evt-3",
    resourceId: "room-2",
    start: new Date(2026, 2, 29, 10, 0),
    end: new Date(2026, 2, 29, 11, 30),
    title: "Design Review",
    color: "#10b981",
  },
];

function App() {
  return <Schedule events={events} resources={resources} />;
}

This renders a day schedule with a toolbar (date navigation + view toggle), resource sidebar, time header, event cards, and a now indicator — all with sensible defaults.

Views

Switch between Day, Week, and Month views:

<Schedule
  events={events}
  resources={resources}
  view="week"
  startDate={new Date(2026, 2, 23)}
/>

Calendar

Calendar displays events in a vertical time axis (like Google Calendar). Resources are used for color and filtering only — there are no resource rows.

Basic Usage

import { Calendar } from "@chronoview/ui";
import type { Resource, TimelineEvent } from "@chronoview/core";

const resources: Resource[] = [
  { id: "work", title: "Work", color: "#3b82f6" },
  { id: "personal", title: "Personal", color: "#10b981" },
];

const events: TimelineEvent[] = [
  {
    id: "evt-1",
    resourceId: "work",
    start: new Date(2026, 2, 29, 9, 0),
    end: new Date(2026, 2, 29, 10, 30),
    title: "Team Standup",
  },
  {
    id: "evt-2",
    resourceId: "personal",
    start: new Date(2026, 2, 29, 10, 0),
    end: new Date(2026, 2, 29, 11, 0),
    title: "Dentist",
    color: "#8b5cf6",
  },
];

function App() {
  return <Calendar events={events} resources={resources} />;
}

This renders a day calendar with a vertical time axis, overlapping event stacking, toolbar, and now indicator — auto-scrolled to the current time.

Views

<Calendar events={events} resources={resources} view="week" />
<Calendar events={events} resources={resources} view="month" />

Month Modes

Calendar Month supports two display modes:

// Horizontal event bars (default)
<Calendar events={events} resources={resources} view="month" monthMode="bar" />

// List inside each cell
<Calendar events={events} resources={resources} view="month" monthMode="list" />

Labels (i18n)

Calendar text defaults to Korean. Override with the labels prop:

<Calendar
  events={events}
  resources={resources}
  labels={{
    weekdays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
    empty: "No events",
    moreEvents: (count) => `${count} more`,
  }}
/>

Dark Mode

Both Schedule and Calendar follow the system preference (prefers-color-scheme) automatically. No extra setup needed.

To force a specific theme, use the theme prop:

<Schedule events={events} resources={resources} theme="dark" />
<Calendar events={events} resources={resources} theme="dark" />

Class-based (dark, [data-theme="dark"]) selectors are also supported for integration with theme libraries like next-themes.

Event Detail (Tooltip & Popover)

Hover an event to see a built-in tooltip. Click an event to show a custom popover. Works the same way for both Schedule and Calendar:

<Schedule
  events={events}
  resources={resources}
  renderEventDetail={(event, { close }) => (
    <div>
      <h3>{event.title}</h3>
      <p>{event.data?.description}</p>
      <button onClick={close}>Close</button>
    </div>
  )}
/>

To disable the hover tooltip while keeping the popover, add disableTooltip:

<Schedule
  events={events}
  resources={resources}
  disableTooltip
  renderEventDetail={(event, { close }) => (
    <div>
      <h3>{event.title}</h3>
      <button onClick={close}>Close</button>
    </div>
  )}
/>

Controlled Date

By default, Schedule and Calendar manage date state internally. To control it externally, pass date and onDateChange:

import { useState } from "react";

const [date, setDate] = useState(new Date());

<Schedule
  events={events}
  resources={resources}
  date={date}
  onDateChange={setDate}
/>

Customizing Tokens

Override CSS variables to match your design system:

:root {
  --cv-color-event-default: #ff6b00;
  --cv-color-bg: #fafafa;
  --cv-size-sidebar-width: 240px;
}

All available tokens are listed in docs/design/common/design-tokens.md.

Headless Usage

Use @chronoview/react hooks directly for full control over rendering:

pnpm add @chronoview/react @chronoview/core

Schedule Hook

import { useScheduleView } from "@chronoview/react";
import type { Resource, TimelineEvent } from "@chronoview/core";

function CustomSchedule({ events, resources }: {
  events: TimelineEvent[];
  resources: Resource[];
}) {
  const { rows, getEventStyle } = useScheduleView({
    events,
    resources,
    view: "day",
    startDate: new Date(),
  });

  return (
    <div style={{ position: "relative" }}>
      {rows.map((row) => (
        <div key={row.resource.id} style={{ position: "relative", height: row.height }}>
          <span>{row.resource.title}</span>
          {row.events.map((layout) => (
            <div key={layout.event.id} style={getEventStyle(layout)}>
              {layout.event.title}
            </div>
          ))}
        </div>
      ))}
    </div>
  );
}

Calendar Hook

import { useCalendarView } from "@chronoview/react";
import type { Resource, TimelineEvent } from "@chronoview/core";

function CustomCalendar({ events, resources }: {
  events: TimelineEvent[];
  resources: Resource[];
}) {
  const { columns, totalMainSize, getEventStyle } = useCalendarView({
    events,
    resources,
    view: "day",
    startDate: new Date(),
  });

  return (
    <div style={{ position: "relative", height: totalMainSize }}>
      {columns[0]?.events.map((layout) => (
        <div key={layout.event.id} style={getEventStyle(layout, 0, 1)}>
          {layout.event.title}
        </div>
      ))}
    </div>
  );
}

Current Status

0.2.0 — Schedule and Calendar layouts (Day/Week/Month) are available. Grid layout is coming in the next release.

  • Schedule Day/Week/Month: available
  • Calendar Day/Week/Month: available
  • Grid Day: planned (0.3.0)
  • Drag & Drop, Resize: planned (0.4.0)
  • Optimized for desktop (1024px+). Responsive support is planned for a future release.

License

MIT

About

Headless schedule timeline library for React

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors