@dope-dev/vue-calendar
v0.1.1
Published
Multi-calendar Vue 3 component — Gregorian, Jalaali (Persian), and Islamic calendar systems
Maintainers
Readme
@dopedev/vue-calendar
A multi-calendar Vue 3 component supporting Gregorian, Jalaali (Persian), and Islamic calendar systems with full RTL support.
Features
- Three calendar systems: Gregorian, Jalaali (Persian), Islamic (Umm al-Qura)
- Three view modes: monthly, weekly, daily
- RTL layout support
- Fully customizable header via slot
- Event display with color, duration, and full-day support
- Dark mode via CSS custom properties
- TypeScript support
Installation
npm install @dopedev/vue-calendar
# or
pnpm add @dopedev/vue-calendarSetup
Import the stylesheet once in your app entry point:
import "@dopedev/vue-calendar/style.css";Nuxt:
// nuxt.config.ts
export default defineNuxtConfig({
css: ["@dopedev/vue-calendar/style.css"],
});Basic Usage
<script setup lang="ts">
import { ref } from "vue";
import { VueCalendar } from "@dopedev/vue-calendar";
import type { CalendarEvent } from "@dopedev/vue-calendar";
const events = ref<CalendarEvent[]>([
{
id: 1,
title: "Team Meeting",
date: new Date(),
time: "10:00",
duration: 60,
color: "#3b82f6",
},
]);
</script>
<template>
<div style="height: 600px">
<VueCalendar :events="events" />
</div>
</template>The component fills its container — give the parent a fixed height.
Props
| Prop | Type | Default | Description |
| -------------- | -------------------------------- | ----------------------- | ---------------------------------------------------------- |
| events | CalendarEvent[] | [] | Events to display |
| mode | CalendarMode | 'monthly' | View mode: 'monthly', 'weekly', 'daily' |
| locale | string | 'en-US' | BCP 47 locale tag used for day/month names |
| calendarType | CalendarType | 'gregory' | Calendar system: 'gregory', 'persian', 'islamic-uma' |
| startOfWeek | number | 0 | First day of week: 0 = Sunday … 6 = Saturday |
| hours | { start: number; end: number } | { start: 0, end: 24 } | Visible hour range in weekly/daily view |
| initialDate | Date | new Date() | Date the calendar opens on |
v-model
mode supports two-way binding:
<VueCalendar v-model:mode="mode" />Events
| Event | Payload | Description |
| -------------- | ---------------------------- | ----------------------------------------------------- |
| update:mode | CalendarMode | Fired when the mode changes |
| range-change | { start: Date; end: Date } | Fired on mount and whenever the visible range changes |
| event-click | CalendarEvent | Fired when an event is clicked |
Header Slot
Replace the default header entirely with the #header slot. All navigation and mode control is exposed through slot props:
<VueCalendar :events="events" v-model:mode="mode">
<template #header="{ mode, range, next, prev, setMode }">
<div class="flex items-center gap-2 p-3 border-b">
<button @click="prev">←</button>
<button @click="next">→</button>
<span>{{ range.start.toLocaleDateString() }}</span>
<div class="ml-auto flex gap-1">
<button
v-for="m in ['monthly', 'weekly', 'daily'] as const"
:key="m"
@click="setMode(m)"
:class="mode === m ? 'font-bold' : ''"
>
{{ m }}
</button>
</div>
</div>
</template>
</VueCalendar>Slot props
| Prop | Type | Description |
| --------- | ------------------------------ | ------------------------------- |
| mode | CalendarMode | Current view mode |
| range | { start: Date; end: Date } | Currently visible date range |
| next | () => void | Navigate to the next period |
| prev | () => void | Navigate to the previous period |
| setMode | (mode: CalendarMode) => void | Switch view mode |
Calendar Systems
Gregorian (English)
<VueCalendar calendar-type="gregory" locale="en-US" :start-of-week="1" />Jalaali / Persian (RTL)
Wrap the component in dir="rtl" to get correct RTL layout. Note that next and prev in the header slot remain semantically correct — swap their visual arrow directions instead.
<div dir="rtl">
<VueCalendar
calendar-type="persian"
locale="fa-IR"
:start-of-week="6"
/>
</div>Islamic / Umm al-Qura (RTL)
<div dir="rtl">
<VueCalendar
calendar-type="islamic-uma"
locale="ar-SA"
:start-of-week="0"
/>
</div>Customizing Event Display
You can override how events are rendered in the time‑grid (weekly/daily) and in the mobile monthly list.
- Desktop time‑grid: use the
#eventslot. - Mobile event list: use the
#event-mobileslot.
<VueCalendar :events="events">
<!-- Custom desktop event -->
<template #event="{ event }">
<div :style="{ background: event.color || '#3b82f6', padding: '4px', borderRadius: '6px' }">
{{ event.title }}
</div>
</template>
<!-- Custom mobile list event -->
<template #event-mobile="{ event }">
<div class="flex items-center gap-2">
<span class="font-bold">{{ event.title }}</span>
<span class="text-sm text-gray-500">{{ event.time }}</span>
</div>
</template>
</VueCalendar>CalendarEvent
interface CalendarEvent {
id: number | string;
date: Date | string; // date of the event
time: string; // 'HH:mm' format
title: string;
duration?: number; // minutes (used in weekly/daily view)
color?: string; // hex or CSS value; defaults to --cal-primary
isFullDay?: boolean;
raw?: any; // attach your original API payload here
}Theming
The calendar exposes a set of CSS custom properties for colours. You can override them on :root for the light theme and inside a .dark selector for the dark theme.
| CSS Variable | Description | Light default | Dark default |
| ------------------------- | ------------------------------------------ | ------------- | ------------ |
| --color-surface | Main background | #ffffff | #151823 |
| --color-surface-variant | Card / cell secondary background | #f8f8fa | #242836 |
| --color-on-surface | Primary text colour | #2c2c2e | #ffffff |
| --color-primary | Accent colour, event background fallback | #1a9d90 | #40b8ac |
| --color-error | Error colour (weekends, holidays, pointer) | #e52b16 | #ea5545 |
| --color-outline | Standard border colour | #d1d0d2 | #605f63 |
| --color-outline-variant | Light border colour | #f0f0f0 | #3a393c |
Today badge gradient
You can change the gradient used for the “today” circle:
| Variable | Light default | Dark default |
| ---------------------- | ----------------------------------------------------- | ----------------------------------------------------- |
| --cal-today-bg-light | radial-gradient(circle at 70% 0%, #10121b, #393e4d) | – |
| --cal-today-bg-dark | – | radial-gradient(circle at 70% 0%, #d1d0d2, #9b9a9d) |
Example customisation:
:root {
--color-surface: #ffffff;
--color-primary: #ff6b6b;
--cal-today-bg-light: radial-gradient(circle at 70% 0%, #4a00e0, #8e2de2);
}
.dark {
--color-surface: #111827;
--color-primary: #ff8787;
--cal-today-bg-dark: radial-gradient(circle at 70% 0%, #ffd700, #ff8c00);
}Exposed Methods
When using a template ref, the component exposes:
const cal = ref<InstanceType<typeof VueCalendar>>();
cal.value?.goNext(); // navigate forward
cal.value?.goPrev(); // navigate backward
cal.value?.setMode("weekly"); // change view mode
cal.value?.currentRange; // { start: Date, end: Date }TypeScript
All public types are exported from the package root:
import type {
CalendarEvent,
CalendarMode,
CalendarType,
CalendarDay,
CalendarDateRange,
CalendarTimeRange,
} from "@dopedev/vue-calendar";Development
pnpm install
pnpm dev # dev sandbox at http://localhost:5173
pnpm type-check # TypeScript check
pnpm build:lib # build the distributable packageRun the Nuxt example
pnpm build:lib
cd examples/nuxt-example
pnpm install
pnpm dev # http://localhost:3000Publishing
npm login # log in with the @dopedev org account
npm publish # prepublishOnly runs build:lib automaticallyLicense
MIT
