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

react-attendance-calendar

v2.4.6

Published

A responsive React attendance calendar component with TypeScript support

Readme

React Attendance Calendar

A modern, responsive React attendance calendar with a compound component architecture. Style it with classes, swap out navigation buttons, render custom cells — or just drop in the pre-composed version and go.

Features

  • Compound components — compose Calendar.Root, Header, Title, PrevTrigger, NextTrigger, WeekDays, and Grid any way you like
  • Pre-composed defaultAttendanceCalendar works out of the box with zero config
  • renderCell — full control over every cell's markup and style
  • useCalendar() hook — headless access to all calendar state for completely custom UIs
  • classNames object — one clean prop for cell, present, absent, today, outside styles
  • Responsive — auto-switches between 7 and 14 columns based on container width
  • TypeScript — full type safety and IntelliSense
  • Multi-month data — provide attendance for multiple months at once

Installation

npm install react-attendance-calendar

Import the CSS once in your app entry:

import "react-attendance-calendar/styles.css";

The package ships pre-compiled CSS. If you use Tailwind CSS v4, you can further customize via className and classNames props.

Quick Start

import { useState } from "react";
import { AttendanceCalendar } from "react-attendance-calendar";
import "react-attendance-calendar/styles.css";

function App() {
  const [view, setView] = useState({ year: 2024, monthIndex: 0 });

  const data = {
    year: 2024,
    monthIndex: 0,
    presentDays: new Set([1, 2, 3, 5, 8, 9, 10]),
    absentDays: new Set([4, 11]),
  };

  return (
    <AttendanceCalendar
      view={view}
      onChangeView={setView}
      attendanceData={data}
      onDateClick={(day, month, year) => console.log(day, month, year)}
    />
  );
}

Usage

Pre-composed (simple)

The AttendanceCalendar component is a ready-to-use calendar with sensible defaults. Pass a classNames object to customize cell styles without touching the layout.

<AttendanceCalendar
  view={view}
  onChangeView={setView}
  attendanceData={data}
  classNames={{
    cell: "rounded-full",
    present: "bg-teal-500 shadow-md",
    absent: "bg-rose-500",
    today: "ring-2 ring-blue-400",
    outside: "opacity-20",
  }}
/>

Compound components (full control)

Build your own layout with Calendar.* components. Place the title, navigation buttons, weekday headers, and grid wherever you want.

import { Calendar } from "react-attendance-calendar";
import "react-attendance-calendar/styles.css";

function MyCalendar() {
  const [view, setView] = useState({ year: 2024, monthIndex: 0 });

  return (
    <Calendar.Root
      view={view}
      onChangeView={setView}
      attendanceData={data}
      onDateClick={(day, month, year) => console.log(day, month, year)}
    >
      <Calendar.Header>
        <Calendar.Title className="text-indigo-700" />
        <div className="flex gap-2">
          <Calendar.PrevTrigger className="rounded-full bg-indigo-500 text-white">
            ←
          </Calendar.PrevTrigger>
          <Calendar.NextTrigger className="rounded-full bg-indigo-500 text-white">
            →
          </Calendar.NextTrigger>
        </div>
      </Calendar.Header>
      <Calendar.WeekDays dayClassName="text-indigo-400" />
      <Calendar.Grid
        classNames={{
          present: "bg-indigo-500",
          absent: "bg-pink-500",
        }}
      />
    </Calendar.Root>
  );
}

Custom title format

Use format for full control over the title markup, or keep the default layout and style the month (className on the <h2>) and year (yearClassName on the year span) separately.

Default title with separate year styling

className applies to the whole heading (<h2>). yearClassName applies only to the year number and overrides the default text-slate-500 (merged with tailwind-merge, so a new text-* class wins).

<Calendar.Title
  className="text-indigo-900"
  yearClassName="text-indigo-600"
/>

Fully custom title

<Calendar.Title
  format={(monthName, year) => (
    <span className="text-lg font-medium">
      {monthName} / {year}
    </span>
  )}
/>

Custom cell rendering

Use renderCell on Calendar.Grid (or the pre-composed AttendanceCalendar) for complete control over each cell's markup. The callback receives a CellData object with all the state you need.

<Calendar.Grid
  renderCell={(cell) => (
    <div
      className={`w-full aspect-square grid place-items-center rounded-xl text-sm ${
        cell.isPresent
          ? "bg-green-100 text-green-700"
          : cell.isAbsent
            ? "bg-red-100 text-red-700"
            : cell.isToday
              ? "bg-blue-600 text-white"
              : "text-slate-600"
      }`}
    >
      {cell.day}
      {cell.isPresent && <span className="text-[10px]">✓</span>}
      {cell.isAbsent && <span className="text-[10px]">✗</span>}
    </div>
  )}
/>

Headless with useCalendar()

For a completely custom UI, use the hook inside a Calendar.Root:

import { Calendar, useCalendar } from "react-attendance-calendar";

function HeadlessCalendar() {
  const { view, monthName, goPrev, goNext, cells, currentMonthData, today, columns } =
    useCalendar();

  // Build any UI you want with full access to calendar state
  return <div>{/* your custom markup */}</div>;
}

function App() {
  const [view, setView] = useState({ year: 2024, monthIndex: 0 });

  return (
    <Calendar.Root view={view} onChangeView={setView} attendanceData={data}>
      <HeadlessCalendar />
    </Calendar.Root>
  );
}

Custom cell sizes

// Square cells
<AttendanceCalendar view={view} onChangeView={setView} cellSize={50} />

// Custom width and height
<AttendanceCalendar view={view} onChangeView={setView} cellWidth={80} cellHeight={50} />

// Compact
<AttendanceCalendar
  view={view}
  onChangeView={setView}
  cellSize={32}
  classNames={{ cell: "rounded-full text-xs" }}
/>

Multi-month data

Pass an array to attendanceData to pre-load multiple months. Navigation between loaded months is instant.

const data: AttendanceData = [
  {
    year: 2024,
    monthIndex: 0,
    presentDays: new Set([1, 2, 3, 5, 8, 9, 10]),
    absentDays: new Set([4, 11]),
  },
  {
    year: 2024,
    monthIndex: 1,
    presentDays: new Set([1, 2, 5, 6, 7]),
    absentDays: new Set([3, 4, 8]),
  },
];

<AttendanceCalendar view={view} onChangeView={setView} attendanceData={data} />;

API Reference

AttendanceCalendar (pre-composed)

| Prop | Type | Default | Description | | --- | --- | --- | --- | | view | MonthView | current month | Current month and year | | onChangeView | (view: MonthView) => void | required | Month navigation callback | | attendanceData | AttendanceData | — | Present/absent days (single or array) | | onDateClick | (day, month, year) => void | — | Date click callback | | showNavigation | boolean | true | Show header with nav buttons | | showWeekDays | boolean | true | Show weekday labels | | className | string | — | Root container class | | classNames | GridClassNames | — | Cell style overrides (see below) | | cellSize | number | — | Square cell size in px | | cellWidth | number | — | Cell width in px | | cellHeight | number | — | Cell height in px | | renderCell | (state: CellData) => ReactNode | — | Custom cell renderer |

GridClassNames

type GridClassNames = {
  cell?: string;    // Base class for all cells
  present?: string; // Present-day cells
  absent?: string;  // Absent-day cells
  today?: string;   // Today's cell (merged last, wins over present/absent)
  outside?: string; // Days outside current month
};

CellData

Passed to renderCell:

type CellData = {
  day: number;
  date: Date;
  inCurrentMonth: boolean;
  isPresent: boolean;
  isAbsent: boolean;
  isToday: boolean;
  isClickable: boolean;
};

Compound Components

| Component | Props | Description | | --- | --- | --- | | Calendar.Root | view, onChangeView, attendanceData, onDateClick, className, children | Context provider and container | | Calendar.Header | className, children | Flex wrapper for title + nav | | Calendar.Title | className, yearClassName?, format? | Month/year heading — yearClassName styles the year span only (default year color: text-slate-500) | | Calendar.PrevTrigger | all <button> props | Previous month button | | Calendar.NextTrigger | all <button> props | Next month button | | Calendar.WeekDays | className, dayClassName, labels? | Weekday labels row | | Calendar.Grid | className, classNames, cellSize, cellHeight, cellWidth, renderCell | Date grid |

useCalendar() Hook

Returns all calendar state when used inside Calendar.Root:

const {
  view,            // MonthView — current month/year
  monthName,       // string — e.g. "January"
  today,           // { day, month, year }
  currentMonthData,// MonthAttendanceData | undefined
  columns,         // number — 7 or 14 (responsive)
  cells,           // { day, inCurrentMonth }[]
  weekdayLabels,   // string[]
  goPrev,          // () => void
  goNext,          // () => void
  onDateClick,     // ((day, month, year) => void) | undefined
} = useCalendar();

Types

type MonthView = {
  year: number;
  monthIndex: number; // 0-11
};

type MonthAttendanceData = {
  year: number;
  monthIndex: number;
  presentDays: Set<number>;
  absentDays: Set<number>;
};

type AttendanceData = MonthAttendanceData | MonthAttendanceData[];

Default Theme

  • Present — emerald green (emerald-500) with white text
  • Absent — amber orange (amber-500) with white text
  • Today (no data) — dark slate (slate-900) with white text
  • Today (present/absent) — status color + ring highlight
  • Outside month — faded with light border
  • Navigation — rounded buttons with hover/active effects

Responsive Behavior

  • Cells use w-full aspect-square by default — fluid with no overflow
  • Container >= 700px: switches to 14-column layout
  • Narrow / mobile: 7-column layout with touch-friendly sizing
  • Use cellSize, cellWidth, or cellHeight for fixed pixel dimensions

License

MIT © Alamin