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

vue-calendar-temporal

v0.2.0

Published

Temporal-powered, headless-first calendar and date picker library for Vue

Readme

vue-calendar-temporal

Temporal-powered, headless-first calendar & date picker for Vue — month / week (time grid) / year views, Google-Calendar-style event rendering, full i18n/l10n, full a11y, SSR-safe, and shipped as both vdom and Vapor builds.

  • Temporal all the way down — every date is a Temporal.PlainDate (or friends), backed by temporal-polyfill-lite as a ponyfill: no global patching, native-Temporal-compatible.
  • Headless first — components render minimal, semantic, data-vct-tagged markup with the full WAI-ARIA grid / date-picker-dialog patterns; slots expose everything. Opt-in stylesheets when you don't want to start from zero.
  • Tiny — size-limit-enforced budgets, measured minified + brotli: useCalendar alone 2.1 kB, the whole library 10 kB, everything including the Temporal ponyfill 26 kB. Per-module dist output means your bundler only takes what you import.
  • Type safety as API design — the selection mode is a generic: with selection-mode="range" your v-model is { start, end } | null, at compile time. Custom event fields survive normalization fully typed.

Install

vp add vue-calendar-temporal   # or: pnpm add / npm i / yarn add

Quick start

<script setup lang="ts">
import { shallowRef } from "vue";
import {
  CalendarRoot,
  CalendarHeader,
  CalendarTitle,
  CalendarPrevButton,
  CalendarNextButton,
  CalendarTodayButton,
  CalendarMonthView,
  Temporal,
} from "vue-calendar-temporal";
// Opt-in styles (structure + calm default theme, light/dark automatic):
import "vue-calendar-temporal/style.css";

const selected = shallowRef<Temporal.PlainDate | null>(null);

const events = [
  {
    id: "trip",
    title: "Kyoto trip",
    start: Temporal.PlainDate.from("2026-07-24"),
    end: Temporal.PlainDate.from("2026-07-27"), // all-day, inclusive
  },
  {
    id: "sync",
    title: "Design sync",
    start: Temporal.PlainDateTime.from("2026-07-15T09:30"), // timed, 60 min default
  },
];
</script>

<template>
  <CalendarRoot v-model="selected" :events="events" locale="ja-JP">
    <CalendarHeader>
      <CalendarTitle />
      <CalendarTodayButton />
      <CalendarPrevButton />
      <CalendarNextButton />
    </CalendarHeader>
    <CalendarMonthView />
  </CalendarRoot>
</template>

Week and year views are drop-in swaps inside the same root:

<CalendarWeekView :start-hour="7" :end-hour="21" />
<!-- time grid + all-day strip -->
<CalendarWeekView :days="3" />
<!-- rolling 3-day (mobile) -->
<CalendarYearView />
<!-- 12 mini months -->

Date picker

<DatePickerRoot v-model="date" selection-mode="range" locale="ja-JP">
  <DatePickerTrigger />
  <DatePickerContent />  <!-- APG dialog: focus management, Esc, outside-click -->
</DatePickerRoot>

Vapor Mode (Vue ≥ 3.6)

The package ships a Vapor-compiled twin of every component:

import { CalendarRoot, CalendarMonthView } from "vue-calendar-temporal/vapor";

Composables are runtime-agnostic and work in both worlds unchanged.

Composables — the headless-est layer

Everything the components do is a thin binding over fully typed composables you can use directly:

import {
  useCalendar,
  useMonthGrid,
  useCalendarEvents,
} from "vue-calendar-temporal";

const calendar = useCalendar({
  locale: "ja-JP",
  selectionMode: "range", // ⇒ calendar.selected: ComputedRef<DateRange | null>
});

const { grid, weekdays } = useMonthGrid(calendar);
const bound = useCalendarEvents(calendar, () => events);

useCalendar / useDatePicker / useMonthGrid / useWeekGrid / useYearGrid / useCalendarEvents / useNowIndicator, plus the pure layer underneath (buildMonthGrid, layoutEventLanes, layoutTimeGridDay, …) — every option, default, and contract is documented on the symbol itself; your editor's hover is the reference manual.

Styling

Three opt-in sheets, all inside vct.* cascade layers so plain user CSS always wins:

| import | contents | | --------------------------------- | ------------------------------------------------------------------------- | | vue-calendar-temporal/style.css | everything below (the one-liner) | | …/styles/base.css | structure only — grid geometry, event positioning; bring your own theme | | …/styles/theme.css | the default look — oklch + light-dark(), one accent, soft settle easing |

Theming is custom-property overrides only (--vct-accent, --vct-radius, --vct-ease-out, …); dark mode follows color-scheme. Headless usage: skip the CSS entirely and style the data-vct="…" / data-* state attributes yourself.

i18n / l10n

Locale drives everything: month/weekday/hour labels, numbering systems (Arabic-Indic digits included), first day of week and weekend from CLDR, RTL direction (arrow keys invert), Intl.ListFormatted multi-selections. UI strings live in a typed CalendarMessages catalog — override any subset, or wire it to vue-i18n.

Accessibility

APG grid pattern (roving tabindex, arrows / PageUp / PageDown / Shift / Home / End / Enter), aria-current today, localized full-date + event-count cell labels, aria-live title announcements, and the APG date-picker-dialog focus contract. Keyboard users get the same range preview pointer users do.

SSR

No DOM access outside event handlers and onMounted; the current-time indicator only starts ticking client-side. Pass today (and locale / timeZone) for byte-identical server output — there's a test asserting it.

Development

vp install
vp dev              # playground + Musea gallery at /__musea__
vp test             # unit (node) + browser (playwright) projects
vp run ready        # fmt → checks → tests → build
vp run size         # size-limit budgets
vp run release minor  # bump PR → auto-merge → tag → npm via OIDC

Every PR gets a deployed Musea gallery preview and a pkg.pr.new package automatically.

License

MIT