npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@emoory/ey-calendar

v0.4.0

Published

EyCalendar - A headless, themeable React calendar component for modern applications

Readme

@emoory/ey-calendar

A React calendar component designed for building scheduling applications. Headless, themeable, and framework-agnostic styling.

npm version npm downloads License: MIT TypeScript PRs Welcome

Features

  • Callback-driven integration for your own state and backend logic
  • Day, week, month, and planning views
  • Full CSS bundle, structure-only CSS, theme-only CSS, or fully unstyled mode
  • Drag and drop with resize support
  • English, French, and German locale helpers
  • React 18 and React 19 peer support
  • ESM + CJS package surface with stable root exports
  • TypeScript-first public API

Philosophy

EyCalendar is built around three practical ideas:

1. Callback-driven integration

EyCalendar renders your events and emits callbacks for interactions. You keep the source of truth in local state, Redux, Zustand, or your backend, and decide how updates are persisted.

  • Integrate with any state management approach
  • Connect to REST, GraphQL, WebSockets, or local-only flows
  • Keep permission rules, validation, and optimistic updates in your app
  • Use convenience callbacks like onEventCreate when you want to return a new event directly

2. Headless styling

Structure and visuals are intentionally separated:

  • Structure: layout, positioning, and grid logic are handled internally
  • Theme: visual classes can be layered with the theme prop
  • Headless: use unstyled with classNames when you want full control

3. Framework-agnostic styling

EyCalendar works with plain CSS, CSS Modules, Tailwind, or any other class-based system.

Installation

npm install @emoory/ey-calendar
# or
pnpm add @emoory/ey-calendar
# or
yarn add @emoory/ey-calendar

Quick Start

import { useState } from "react";
import { EyCalendar, type EyCalendarEvent } from "@emoory/ey-calendar";
import "@emoory/ey-calendar/styles.css";

function App() {
  const [events, setEvents] = useState<EyCalendarEvent[]>([
    {
      id: "1",
      title: "Team Meeting",
      start: new Date(2026, 0, 20, 10, 0),
      end: new Date(2026, 0, 20, 11, 0),
    },
  ]);

  return (
    <EyCalendar
      events={events}
      defaultView="week"
      onEventClick={(event) => {
        console.log("Clicked:", event);
      }}
      onEventDrop={(event, dropTarget) => {
        setEvents((prev) =>
          prev.map((currentEvent) =>
            currentEvent.id === event.id
              ? {
                  ...currentEvent,
                  start: dropTarget.dateStart,
                  end: dropTarget.dateEnd,
                }
              : currentEvent
          )
        );
      }}
      onTimeSlotClick={(date) => {
        setEvents((prev) => [
          ...prev,
          {
            id: crypto.randomUUID(),
            title: "New Event",
            start: date,
            end: new Date(date.getTime() + 60 * 60 * 1000),
          },
        ]);
      }}
    />
  );
}

Styling

EyCalendar uses namespaced ey-cal-* classes and supports three main styling modes.

CSS imports

import "@emoory/ey-calendar/styles.css";
import "@emoory/ey-calendar/styles/structure.css";
import "@emoory/ey-calendar/styles/theme.css";

CSS variables

Override theme variables on .ey-cal-root:

.ey-cal-root {
  --ey-cal-primary: #3b82f6;
  --ey-cal-background: #ffffff;
  --ey-cal-foreground: #1f2937;
  --ey-cal-border: #e5e7eb;
  --ey-cal-radius: 0.5rem;
}

Tailwind or class-based theme overlay

Copy the example theme from GitHub and adapt it locally:

  • Theme source: https://github.com/zuher83/ey-calendar/blob/main/apps/examples/themes/tailwind.ts
import { tailwindTheme } from "./themes/tailwind";

<EyCalendar events={events} theme={tailwindTheme} />;

You can then override specific visual classes:

<EyCalendar
  events={events}
  theme={{
    ...tailwindTheme,
    root: "bg-white rounded-xl shadow-2xl",
    toolbar: "bg-slate-900 text-white",
    eventBar: "rounded-lg shadow-lg",
  }}
/>

Fully headless mode

Use unstyled with classNames when you want to own the full styling layer:

<EyCalendar
  events={events}
  unstyled
  classNames={{
    root: "my-calendar",
    toolbar: "my-toolbar",
    weekView: "my-week-view",
  }}
/>

Stable Root Imports

The package root intentionally exposes the stable consumer surface:

import {
  cn,
  deCalendar,
  enCalendar,
  EyCalendar,
  EyCalendarToolbar,
  frCalendar,
  resolveTheme,
} from "@emoory/ey-calendar";
import type {
  DropTarget,
  EyCalendarCallbacks,
  EyCalendarClassKey,
  EyCalendarClassNames,
  EyCalendarEvent,
  EyCalendarOptions,
  EyCalendarThemeClasses,
  TimeSlot,
} from "@emoory/ey-calendar";

Do not rely on internal package paths. If you need the example Tailwind overlay, copy it from GitHub instead of importing from a non-public subpath.

Callback-driven integration

Event interactions

  • onEventClick
  • onEventDoubleClick
  • onEventHover
  • onEventDrag
  • onEventDrop
  • onEventResize
  • onEventUpdate - Generic update callback with optimistic rollback support via revert()
  • onEventDelete
  • onEventCreate

Time slots and navigation

  • onTimeSlotClick
  • onTimeSlotDoubleClick
  • onDateChange
  • onViewChange
  • onDateRangeChange
  • onShowMoreClick
  • onRenderComplete
  • onScrollChange

Backend integration example

<EyCalendar
  events={events}
  onEventUpdate={async (eventId, updates, revert) => {
    try {
      await fetch(`/api/events/${eventId}`, {
        method: "PATCH",
        body: JSON.stringify(updates),
      });
    } catch (error) {
      revert();
    }
  }}
  onTimeSlotClick={(date) => {
    openCreateEventModal(date);
  }}
/>

API Overview

Core public props and callbacks:

interface EyCalendarProps {
  events?: EyCalendarEvent[];
  defaultView?: "day" | "week" | "month" | "planning";
  defaultDate?: Date;
  height?: string | number;
  width?: string | number;
  theme?: Partial<Record<EyCalendarClassKey, string>>;
  unstyled?: boolean;
  classNames?: EyCalendarClassNames;

  onEventClick?: (event: EyCalendarEvent, e: React.MouseEvent) => void;
  onEventDoubleClick?: (event: EyCalendarEvent, e: React.MouseEvent) => void;
  onEventHover?: (event: EyCalendarEvent, e: React.MouseEvent) => void;
  onEventDrag?: (
    event: EyCalendarEvent,
    newStart: Date,
    newEnd: Date,
    newResourceId?: string
  ) => void;
  onEventResize?: (event: EyCalendarEvent, newStart: Date, newEnd: Date) => void;
  onEventDrop?: (event: EyCalendarEvent, dropTarget: DropTarget) => void;
  onTimeSlotClick?: (date: Date, e: React.MouseEvent, resourceId?: string) => void;
  onTimeSlotDoubleClick?: (date: Date, e: React.MouseEvent, resourceId?: string) => void;
  onEventCreate?: (timeSlot: TimeSlot, resourceId?: string) => EyCalendarEvent | void;
  onEventUpdate?: (eventId: string, updates: Partial<EyCalendarEvent>, revert: () => void) => void;
  onEventDelete?: (eventId: string) => void;
  onViewChange?: (view: ViewMode, date: Date) => void;
  onDateChange?: (date: Date) => void;
  onDateRangeChange?: (range: DateRange) => void;
  onShowMoreClick?: (
    date: Date,
    hiddenEvents: EyCalendarEvent[],
    allEvents: EyCalendarEvent[]
  ) => void;
  onRenderComplete?: (renderTime: number, eventCount: number) => void;
  onScrollChange?: (position: { x: number; y: number }) => void;

  options?: Partial<EyCalendarOptions>;
}

Compatibility

  • React 18 and React 19 via peer dependencies
  • Stable root import from @emoory/ey-calendar
  • Published CSS entrypoints: styles.css, styles/structure.css, styles/theme.css
  • Works with bundled CSS, theme overlays, or fully headless unstyled mode
  • Reference integrations available for Vite + React and Next.js App Router

Current Status

Available today:

  • Day, week, month, and planning views
  • Click, double-click, drag, resize, create, delete, and month overflow interactions
  • Callback-driven integration with your own state and backend flows
  • Full CSS bundle, structure-only CSS, theme-only CSS, and headless styling overrides
  • English, French, and German locale helpers
  • Localized ARIA labels, live view announcements, and keyboard date navigation for week/month surfaces
  • Hot-path optimizations for time slot calculations and week event grouping
  • Curated npm export surface with stable root imports

Roadmap Snapshot

Before 1.0, the main remaining work is:

  • Finalize public API guarantees
  • Raise automated coverage toward the 1.0 target
  • Expand the example gallery and complete the API documentation
  • Add repository-level React 18 consumer validation in addition to the current React 19 consumers

Not in the current public contract:

  • Resource axis / multi-resource scheduling
  • Virtualization

Future enhancements tracked separately:

  • Year view
  • Planning/List view improvements
  • Mobile views and touch interactions

Full roadmap: https://github.com/zuher83/ey-calendar/blob/main/ROADMAP.md

Examples

  • Next.js App Router: https://github.com/zuher83/ey-calendar/tree/main/apps/examples/nextjs-app
  • Vite + React: https://github.com/zuher83/ey-calendar/tree/main/apps/examples/vite-react
  • Tailwind theme source: https://github.com/zuher83/ey-calendar/blob/main/apps/examples/themes/tailwind.ts

Using the Tailwind theme example

  1. Copy the theme file into your project:

    curl -o src/themes/calendar-tailwind.ts https://raw.githubusercontent.com/zuher83/ey-calendar/main/apps/examples/themes/tailwind.ts
  2. Import and use it:

    import { tailwindTheme } from "./themes/calendar-tailwind";
    
    <EyCalendar events={events} theme={tailwindTheme} />;
  3. Customize it with object spread:

    <EyCalendar
      events={events}
      theme={{
        ...tailwindTheme,
        eventBar: "rounded-xl shadow-xl hover:shadow-2xl",
      }}
    />

Links

  • Repository: https://github.com/zuher83/ey-calendar
  • Playground: https://stackblitz.com/github/zuher83/ey-calendar/tree/main/apps/playground
  • Changelog: https://github.com/zuher83/ey-calendar/blob/main/packages/ey-calendar/CHANGELOG.md
  • Contributing: https://github.com/zuher83/ey-calendar/blob/main/CONTRIBUTING.md
  • Roadmap: https://github.com/zuher83/ey-calendar/blob/main/ROADMAP.md
  • Issues: https://github.com/zuher83/ey-calendar/issues
  • Discussions: https://github.com/zuher83/ey-calendar/discussions

Status

EyCalendar is in active development. The core functionality is stable, but breaking changes may occur before v1.0.

License

MIT © Zuher ELMAS - Emoory Team