beautify-event
v1.2.1
Published
A beautiful, customizable React event calendar with month, week, day, and resource views. Built with Radix UI and Tailwind CSS.
Maintainers
Readme
Beautify Event
A beautiful, fully customizable React event calendar component with month, week, day, and resource views. Built with Radix UI, Tailwind CSS, and date-fns.
Features
- Multiple Views: Month, Week, Day, and Resource views
- Responsive: Mobile-optimized with collapsible month picker and horizontal-scrolling week view
- Localization: Built-in support for English, French, and Arabic (extensible)
- Drag & Drop: Create events by dragging on empty slots; move events by dragging
- Current Time Line: Optional horizontal line showing the current time in day/week views
- Customizable: Custom event renderers, headers, themes, and styling
- TypeScript: Full type definitions included
Installation
npm install beautify-eventPeer Dependencies
Beautify Event requires the following peer dependencies. Install them if not already present:
npm install react react-dom date-fnsFor full styling and component support, you'll also need:
- Tailwind CSS (v3 or v4)
- Radix UI primitives (or shadcn/ui)
- lucide-react (or ensure icons are available)
Styling (choose one)
Option A — Import pre-built CSS (recommended, zero config)
import "beautify-event/styles.css"
import { EventCalendar } from "beautify-event"This includes all styles the calendar needs. The calendar provides its own design tokens (scoped to .event-calendar-root), so it works with or without shadcn/ui.
Option B — Tailwind content (if you already use Tailwind and prefer tree-shaking)
Add beautify-event to your Tailwind content so its classes are included:
Tailwind v3 (tailwind.config.js):
content: [
"./src/**/*.{js,ts,jsx,tsx}",
"./node_modules/beautify-event/**/*.js",
],Tailwind v4 — Add ./node_modules/beautify-event/dist/**/*.js to your @source paths.
Also ensure your project defines the design tokens (primary, border, muted, accent, card, etc.) or use Option A.
Quick Start
import "beautify-event/styles.css"
import { EventCalendar } from "beautify-event"
import type { CalendarEvent } from "beautify-event"
const events: CalendarEvent[] = [
{
id: "1",
title: "Team Meeting",
start: new Date(2026, 2, 10, 9, 0),
end: new Date(2026, 2, 10, 10, 0),
color: "#3b82f6",
},
]
export default function App() {
return (
<div className="h-[600px]">
<EventCalendar events={events} />
</div>
)
}Usage
Basic Example
<EventCalendar
events={events}
defaultDate={new Date()}
defaultView="week"
views={["month", "week", "day"]}
/>Controlled Mode
const [date, setDate] = useState(new Date())
const [view, setView] = useState<ViewType>("week")
<EventCalendar
events={events}
date={date}
view={view}
onDateChange={setDate}
onViewChange={setView}
/>With Resources (Rooms, etc.)
const resources: Resource[] = [
{ id: "room-1", name: "Conference Room A", color: "#3b82f6" },
{ id: "room-2", name: "Meeting Room B", color: "#10b981" },
]
<EventCalendar
events={events}
resources={resources}
views={["month", "week", "day", "resource"]}
/>Event Handlers
<EventCalendar
events={events}
onEventClick={(event) => console.log("Clicked:", event)}
onEventDoubleClick={(event) => openEditModal(event)}
onSlotClick={(slot) => createEvent(slot)}
onSlotDoubleClick={(slot) => createEvent(slot)}
onDayClick={(date) => navigateToDay(date)}
onDateChange={(date) => setSelectedDate(date)}
onRangeChange={(range) => fetchEvents(range)}
/>Drag & Drop
<EventCalendar
events={events}
enableDragToCreate
enableDragToMove
onEventCreate={(slotInfo) => {
const newEvent = { id: "new-1", title: "New Event", ...slotInfo }
setEvents((prev) => [...prev, newEvent])
}}
onEventMove={({ event, newStart, newEnd }) => {
setEvents((prev) =>
prev.map((e) =>
e.id === event.id ? { ...e, start: newStart, end: newEnd } : e
)
)
}}
/>Calendar Options
Pass configuration via calendarOptions:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| startHour | number | 0 | Start hour for time series (0-23) |
| endHour | number | 24 | End hour (use 24 for full day) |
| timeFormat | "12h" \| "24h" | "12h" | Hour label format |
| weekStartsOn | 0-6 | 0 | First day of week (0 = Sunday) |
| hourHeight | number | 64 | Height of each hour slot in pixels |
| timeSeriesMaxHeight | number \| string | 400 | Max height for day/week grid; enables scrolling |
| showCurrentTimeLine | boolean | true | Show horizontal line at current time |
| maxEventsPerDay | number | 3 | Events to show before "+X more" in month view |
| defaultEventColor | string | "#3b82f6" | Default event color |
| defaultResourceColor | string | "#6366f1" | Default resource color |
| locale | string | "en-US" | Locale for formatting |
<EventCalendar
events={events}
calendarOptions={{
startHour: 8,
endHour: 20,
timeFormat: "24h",
weekStartsOn: 1,
locale: "fr",
timeSeriesMaxHeight: 500,
showCurrentTimeLine: true,
}}
/>Localization
Built-in locales: English (en, en-US), French (fr), Arabic (ar).
<EventCalendar
events={events}
calendarOptions={{ locale: "fr" }}
/>To integrate with your app's i18n:
// With next-intl
const locale = useLocale()
// With react-i18next
const { i18n } = useTranslation()
<EventCalendar
events={events}
calendarOptions={{ locale: i18n.language }}
/>Themes
// Use system/app theme
<EventCalendar events={events} />
// Force light or dark
<EventCalendar events={events} theme="dark" />
// Custom theme variables
<EventCalendar
events={events}
themeVars={{
"--primary": "#6366f1",
"--background": "#0f172a",
"--foreground": "#f8fafc",
}}
/>Props Reference
EventCalendar
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| events | CalendarEvent[] | required | Events to display |
| resources | Resource[] | [] | Resources for resource view |
| date | Date | - | Controlled current date |
| defaultDate | Date | new Date() | Initial date (uncontrolled) |
| view | ViewType | - | Controlled view |
| defaultView | ViewType | "month" | Initial view (uncontrolled) |
| views | ViewType[] | ["month","week","day","resource"] | Available views |
| calendarOptions | CalendarOptions | {} | Calendar configuration |
| showNavigation | boolean | true | Show prev/next buttons |
| showViewSwitcher | boolean | true | Show view toggle |
| showTodayButton | boolean | true | Show Today button |
| className | string | - | Container class name |
| loading | boolean | false | Loading state |
| theme | "light" \| "dark" \| "system" | "system" | Theme mode |
| themeVars | Record<string, string> | - | CSS variable overrides |
| enableDragToCreate | boolean | false | Allow drag to create events |
| enableDragToMove | boolean | false | Allow drag to move events |
| mobileBreakpoint | "sm" \| "md" \| "lg" | "md" | Breakpoint for mobile layout |
| showMobileMonthPicker | boolean | true | Show month picker on mobile |
CalendarEvent
interface CalendarEvent {
id: string
title: string
start: Date
end: Date
color?: string
resourceId?: string
description?: string
allDay?: boolean
}Resource
interface Resource {
id: string
name: string
color?: string
}Custom Renderers
Custom Event Content
<EventCalendar
events={events}
renderEvent={(event, view) => (
<div className="custom-event">
<strong>{event.title}</strong>
{event.description && <p>{event.description}</p>}
</div>
)}
/>Custom Header
<EventCalendar
events={events}
renderHeader={({ date, view, title, onNavigate, onToday }) => (
<div className="flex items-center justify-between">
<h1>{title}</h1>
<div>
<button onClick={() => onNavigate("prev")}>Prev</button>
<button onClick={onToday}>Today</button>
<button onClick={() => onNavigate("next")}>Next</button>
</div>
</div>
)}
/>Selected Event / Slot UI
<EventCalendar
events={events}
renderSelectedEvent={({ event, onClose }) =>
event && (
<Sheet open={!!event} onOpenChange={(open) => !open && onClose()}>
<SheetContent>
<SheetHeader>
<SheetTitle>{event.title}</SheetTitle>
</SheetHeader>
<p>{event.description}</p>
</SheetContent>
</Sheet>
)
}
renderSelectedSlot={({ slot, onClose }) => (
// Your slot detail UI
)}
/>Mobile Behavior
On viewports below the mobileBreakpoint:
- Simplified header with week strip
- Month title with expandable month picker (chevron toggle)
- Week view shows ~2 days at a time with horizontal scroll
- Sticky time labels column during horizontal scroll
- Touch-friendly day selection
Exports
// Components
export { EventCalendar, EventCalendarThemeProvider, useCalendar }
// Types
export type {
ViewType,
TimeFormat,
CalendarOptions,
CalendarEvent,
Resource,
SlotInfo,
DateRange,
EventCalendarProps,
HeaderRenderProps,
CalendarConfig,
CalendarTheme,
}
// Utilities
export {
getMonthDays,
getWeekDays,
getEventsForDay,
navigateDate,
getViewTitle,
getViewDateRange,
formatHour,
formatDate,
getDateFnsLocale,
getHoursArray,
createSlotDate,
}Requirements
- React 18+
- Tailwind CSS
- Radix UI (or shadcn/ui components)
- date-fns
Publishing
npm run build:lib # Build dist/
npm publish # Use --otp=XXXXXX if you have 2FA enabledLicense
MIT
