https://github.com/devints47/cal7
A zero-configuration React calendar component for displaying Google Calendar events in a responsive weekly view.
https://github.com/devints47/cal7
calendar calendar-api calendar-component calendar-widget google-calendar google-calendar-api google-calendar-integration nextjs react
Last synced: 8 months ago
JSON representation
A zero-configuration React calendar component for displaying Google Calendar events in a responsive weekly view.
- Host: GitHub
- URL: https://github.com/devints47/cal7
- Owner: devints47
- Created: 2025-07-24T21:40:21.000Z (11 months ago)
- Default Branch: main
- Last Pushed: 2025-09-15T23:32:57.000Z (9 months ago)
- Last Synced: 2025-10-10T04:07:13.391Z (8 months ago)
- Topics: calendar, calendar-api, calendar-component, calendar-widget, google-calendar, google-calendar-api, google-calendar-integration, nextjs, react
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/cal7
- Size: 8.67 MB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
Awesome Lists containing this project
README
# cal7
A zero-configuration React calendar component for displaying Google Calendar events in a responsive weekly view.
## Installation
```bash
npm install cal7
```
## Quick Start
```tsx
import { Calendar } from "cal7";
import "cal7/styles";
// Set environment variable: GOOGLE_CALENDAR_API_KEY=your_api_key
export default function MyApp() {
return ;
}
```
## Zero‑key ICS Quick Start (Recommended)
Use a public Google Calendar ICS feed on the server, then render the client calendar with events. No Google API key required.
1) Server: fetch the ICS and parse to events
```tsx
// app/events/page.tsx (Next.js App Router, Server Component)
import { parseICS } from "cal7";
import "cal7/styles"; // one CSS import
async function getEventsFromICS() {
// Replace with your public Google Calendar ICS URL
const ICS_URL = "https://calendar.google.com/calendar/ical/your_calendar_id%40group.calendar.google.com/public/basic.ics";
const res = await fetch(ICS_URL, { next: { revalidate: 300 } }); // cache 5min
if (!res.ok) throw new Error("Failed to fetch ICS");
const icsText = await res.text();
return parseICS(icsText); // returns CalendarEvent[]
}
export default async function EventsPage() {
const events = await getEventsFromICS();
// Pass serializable events to the client
return ;
}
```
2) Client: render the calendar
```tsx
// components/EventsCalendarClient.tsx ("use client")
"use client";
import { CalendarClient } from "cal7";
export default function EventsCalendarClient({ events }: { events: any[] }) {
return (
);
}
```
3) Theming in a few lines (optional)
```tsx
// app/events/page.tsx (wrap client render)
import { ThemeProvider, type CalendarTheme } from "cal7";
import "cal7/styles";
const theme: CalendarTheme = {
colors: {
primary: "#059669", // brand green
today: "#059669",
todayBackground: "#D1FAE5",
eventBorder: "#A7F3D0",
},
};
export default async function EventsPage() {
const events = await getEventsFromICS();
return (
);
}
```
Notes:
- parseICS focuses on VEVENT blocks, DATE vs DATETIME, Z vs local, and all‑day detection. Recurrence should be pre‑expanded by your provider (Google does this in ICS).
- For private calendars or advanced features (attendees, write access), use the API‑key flow described below.
---
## Next.js App Router Recipe (Client + Server)
- Server components: fetch/parse ICS or fetch via the Google API if you need private calendars.
- Client component: render with the normalized events.
- Styles: `import "cal7/styles"` once (global or server layout), or rely on ThemeProvider tokens to map to CSS variables.
```tsx
// app/layout.tsx
import "cal7/styles";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return {children};
}
```
---
## Placement and Portals (dropdowns, menus)
Dropdown menus can render via a fixed‑position portal to avoid clipping inside modals or containers.
Props (1.2.0):
- AddToCalendarButton, SubscribeButton:
- portalTarget?: HTMLElement | string; defaults to document.body when provided
- dropdownPlacement?: "up" | "down" | "auto" (auto chooses based on available space)
- offset?: number (px), default 8
Example (subscribe opens upward by default):
```tsx
```
Example (explicit portal to body for add‑to‑calendar in a modal):
```tsx
import { AddToCalendarButton } from "cal7";
```
---
## Theming Tokens Reference (excerpt)
Cal7 maps theme tokens to CSS variables. You can set tokens via ThemeProvider or override CSS vars globally.
Colors (examples):
- primary, secondary, background, surface, text, textSecondary, textMuted
- border, borderLight
- today, todayBackground
- eventBackground, eventBorder, eventText
- headerEven, headerOdd, dayEven, dayOdd, dayHover
Other:
- typography: fontFamily, fontSize.{xs|sm|base|lg|xl|2xl}, fontWeight.{normal|medium|semibold|bold}
- spacing: { xs, sm, md, lg, xl, 2xl }
- borderRadius: { none, sm, md, lg, full }
- shadows: { none, sm, md, lg, xl }
- zIndex: { dropdown, modal, tooltip }
CSS example:
```css
:root {
--cal7-color-primary: #059669;
--cal7-color-today: #059669;
--cal7-color-today-background: #D1FAE5;
--cal7-color-event-border: #A7F3D0;
}
```
---
## Accessibility
- Roles: dialog, menu, menuitem with aria‑expanded/aria‑controls bound to triggers
- Modal focus loop (dependency‑free) with Escape and outside‑click dismiss
- Keyboard navigation: arrows in menus, Tab cycle in modal
- Respects prefers‑reduced‑motion and high‑contrast
## Features
- 🚀 **Zero Configuration**: Just set your API key and go
- 📱 **Responsive Design**: Adapts from desktop 7-day view to mobile-friendly layout
- ♿ **Accessibility First**: Full keyboard navigation and screen reader support
- 🎨 **Customizable Theming**: Extensive theme system with CSS custom properties
- 🌙 **Dark Mode**: Built-in dark theme with system preference detection
- 📅 **Add to Calendar**: Device-aware calendar integration (Google, Apple, iCal)
- 🔒 **Secure**: Server-side API key handling, no client-side exposure
- ⚡ **Performance**: Built-in caching and optimized rendering
- 📦 **Zero runtime dependencies** by default; small bundle footprint
- 🎯 **TypeScript**: Full type safety and IntelliSense support
--------

## Framework Compatibility
This package is designed specifically for **React-based frameworks** with the following support levels:
### ✅ Fully Supported
- **Next.js 13+ (App Router)** - Primary target with full server-side rendering support
- **Next.js 12+ (Pages Router)** - Full compatibility with getServerSideProps/getStaticProps
### ⚠️ Partial Support
- **Create React App / Vite** - Client-side only, requires custom `fetcher` prop for API calls
- **Remix** - May work with adaptation, but not officially tested
### ❌ Not Compatible
- **Vue/Nuxt, Svelte/SvelteKit, Angular** - Different framework ecosystems, would need separate packages
**Recommended:** Use with Next.js for the best experience with server-side rendering and secure API key handling.
## Basic Usage
### Server Component (Recommended)
```tsx
import { Calendar } from "cal7";
export default function EventsPage() {
return ;
}
```
### With Theme Provider
```tsx
import { Calendar, ThemeProvider } from "cal7";
const customTheme = {
colors: {
primary: "#3b82f6",
background: "#ffffff",
eventBackground: "#f8fafc",
},
typography: {
fontFamily: "Inter, sans-serif",
customFontUrl:
"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap",
},
};
export default function App() {
return (
);
}
```
## Theming & Customization
Cal7 provides extensive theming capabilities through CSS custom properties and a comprehensive theme system.
### Theme Configuration
```tsx
import { Calendar, ThemeProvider, type CalendarTheme } from "cal7";
const customTheme: CalendarTheme = {
colors: {
// Primary colors
primary: "#3b82f6",
secondary: "#6b7280",
background: "#ffffff",
surface: "#f9fafb",
// Text colors
text: "#111827",
textSecondary: "#374151",
textMuted: "#6b7280",
eventPastText: "#9ca3af", // Color for past events
// Border colors
border: "#e5e7eb",
borderLight: "#f3f4f6",
// State colors
today: "#92400e",
todayBackground: "#fef3c7",
focus: "#3b82f6",
hover: "#f3f4f6",
// Day alternating colors
dayEven: "#fafafa",
dayOdd: "#ffffff",
dayHover: "#f8fafc",
// Header alternating colors
headerEven: "#f3f4f6",
headerOdd: "#f9fafb",
// Event colors
eventBackground: "#ffffff",
eventBorder: "#e5e7eb",
eventText: "#111827",
},
typography: {
fontFamily: "Inter, -apple-system, BlinkMacSystemFont, sans-serif",
customFontUrl:
"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap",
fontSize: {
xs: "0.75rem",
sm: "0.875rem",
base: "1rem",
lg: "1.125rem",
xl: "1.25rem",
"2xl": "1.5rem",
},
fontWeight: {
normal: 400,
medium: 500,
semibold: 600,
bold: 700,
},
},
spacing: {
xs: "0.25rem",
sm: "0.5rem",
md: "1rem",
lg: "1.5rem",
xl: "2rem",
"2xl": "3rem",
},
shadows: {
calendar:
"0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)",
sm: "0 1px 2px rgba(0, 0, 0, 0.05)",
md: "0 2px 4px rgba(0, 0, 0, 0.1)",
lg: "0 4px 6px rgba(0, 0, 0, 0.1)",
xl: "0 10px 15px rgba(0, 0, 0, 0.1)",
},
event: {
height: "auto", // Customizable event section height
width: "100%", // Customizable event width
titleMinHeight: "2.5rem", // Minimum height for event titles (2 lines)
},
};
export default function App() {
return (
);
}
```
### Dark Mode
```tsx
import { ThemeProvider } from "cal7";
export default function App() {
return (
);
}
```
### CSS Custom Properties
You can also customize the calendar using CSS custom properties:
```css
:root {
/* Colors */
--cal7-color-primary: #3b82f6;
--cal7-color-background: #ffffff;
--cal7-color-surface: #f9fafb;
--cal7-color-text: #111827;
--cal7-color-border: #e5e7eb;
/* Day alternating colors */
--cal7-color-day-even: #fafafa;
--cal7-color-day-odd: #ffffff;
--cal7-color-day-hover: #f8fafc;
/* Header alternating colors */
--cal7-color-header-even: #f3f4f6;
--cal7-color-header-odd: #f9fafb;
/* Past events */
--cal7-color-event-past-text: #9ca3af;
/* Typography */
--cal7-font-family: "Inter", sans-serif;
--cal7-font-size-base: 1rem;
--cal7-font-weight-bold: 700;
/* Event customization */
--cal7-event-height: auto;
--cal7-event-width: 100%;
--cal7-event-title-min-height: 2.5rem;
/* Shadows */
--cal7-shadow-calendar: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
/* Spacing */
--cal7-spacing-sm: 0.5rem;
--cal7-spacing-md: 1rem;
--cal7-spacing-lg: 1.5rem;
}
```
### Custom Font Integration
```tsx
const themeWithCustomFont = {
typography: {
fontFamily: "Poppins, sans-serif",
customFontUrl:
"https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap",
},
};
```
## Component Props
### Calendar
| Prop | Type | Default | Description |
| ---------------------- | ------------------------ | ----------- | --------------------------------------------------------- |
| `locale` | `string` | `'en-US'` | Locale for date/time formatting |
| `timeZone` | `string` | `'UTC'` | Timezone for event display |
| `revalidate` | `number` | `300` | Cache revalidation time in seconds |
| `className` | `string` | `''` | Additional CSS classes |
| `theme` | `CalendarTheme` | `undefined` | Custom theme configuration |
| `darkTheme` | `CalendarTheme` | `undefined` | Custom dark theme configuration |
| `mode` | `ThemeMode` | `'light'` | Theme mode: 'light', 'dark', or 'system' |
| `classPrefix` | `string` | `'cal7'` | CSS class prefix for custom styling |
| `showSubscribeButton` | `boolean` | `false` | Show "Subscribe to Calendar!" button with .ics download |
| `fetcher` | `() => Promise` | `undefined` | Custom data fetcher function |
| `onError` | `(error: Error) => void` | `undefined` | Error handler callback |
### ThemeProvider
| Prop | Type | Default | Description |
| -------------------- | ------------------------------- | ------------------ | ------------------------- |
| `config.theme` | `CalendarTheme` | `defaultTheme` | Light theme configuration |
| `config.darkTheme` | `CalendarTheme` | `defaultDarkTheme` | Dark theme configuration |
| `config.mode` | `'light' \| 'dark' \| 'system'` | `'light'` | Theme mode |
| `config.classPrefix` | `string` | `'cal7'` | CSS class prefix |
## Styling Features
### Enhanced Visual Design
- **Drop Shadow**: Entire calendar component has a subtle drop shadow
- **Alternating Colors**: Days and headers alternate background colors for better visual separation
- **Smooth Animations**: Hover effects with scale and smooth transitions
- **Past Event Styling**: Past events are automatically greyed out using theme-appropriate colors
### Event Card Enhancements
- **Clock Icons**: Time displays include clock icons
- **Start/End Times**: Shows both start and end times (e.g., "8:00AM to 10:00PM")
- **Bold Titles**: Event titles are bold and have increased font size
- **Minimum Height**: Event titles have a minimum 2-line height by default
- **Location Icons**: SVG location icons instead of emoji pins
- **Customizable Dimensions**: Event height and width can be customized via theme
### Interactive Features
- **Clickable Links**: Email addresses and URLs in event descriptions are automatically clickable
- **Map Integration**: Event locations are clickable and open in device-appropriate map apps
- **Add to Calendar**: Event modal dates are clickable with add-to-calendar functionality
- **Themed Buttons**: Add-to-calendar buttons match the selected theme (no gradients)
### Subscribe to Calendar Button
When enabled with `showSubscribeButton={true}`, displays a prominent "Subscribe to Calendar!" button that provides:
- **Full Calendar Subscription**: Users can subscribe to the entire calendar feed via URL
- **Download .ics File**: Users can download all calendar events as a local .ics file
- **Upward-Opening Menu**: Dropdown menu opens upward to avoid being cut off
- **Theme Integration**: Button styling matches your current theme with orange gradient
- **Desktop/Mobile Friendly**: Works across all devices and calendar applications
### Navigation Improvements
- **Current Week Indicator**: Shows "Current Week" badge when viewing the current week
- **Themed Borders**: Themed border between week selector and calendar grid
- **Date Format**: Week selector shows dates in "Jul 20 - 26, 2025" format
- **Button Layout**: Navigation arrows positioned left and right of "Today" button
## Environment Setup
Set your Google Calendar API key as an environment variable:
```bash
# .env.local
GOOGLE_CALENDAR_API_KEY=your_api_key_here
```
## TypeScript Support
Cal7 is built with TypeScript and provides full type definitions:
```tsx
import type { CalendarTheme, CalendarEvent, ThemeConfig } from "cal7";
const theme: CalendarTheme = {
colors: {
primary: "#3b82f6",
// ... other theme properties with full IntelliSense
},
};
```
## Accessibility
- **Keyboard Navigation**: Full keyboard support with arrow keys, Enter, Space, and Escape
- **Screen Reader Support**: Comprehensive ARIA labels and live region announcements
- **Focus Management**: Proper focus trapping in modals and logical tab order
- **High Contrast**: Supports high contrast mode preferences
- **Reduced Motion**: Respects user's reduced motion preferences
## Browser Support
- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+
## License
MIT