headless

The same calendar in parts. The keyboard, the state and the accessibility come with them; the markup and the looks are yours.

SuMoTuWeThFrSa

the parts, styled by this site: no qwik-date stylesheet

.day { width: 36px; height: 36px; border-radius: 4px; }
.day[aria-current='date'] { box-shadow: inset 0 -2px 0 #2563eb; }
.day[data-in-range] { background: #2563eb14; color: #2563eb; }
.day[data-selected] { background: #2563eb; color: white; }
.day:disabled { opacity: 0.35; }

The styled Calendar is these parts plus a stylesheet. Use them as in Qwik UI or QDS: put them together and style them by their attributes.

import

import { Calendar, useCalendar } from 'qwik-date/headless';

The same package, another entry point. It also exports the types and formatDate.

anatomy

<Calendar.Root>
  <Calendar.PrevButton />
  <Calendar.Title />
  <Calendar.NextButton />
  <Calendar.Grid>
    <Calendar.GridHead />
    <Calendar.GridBody />
  </Calendar.Grid>
  <Calendar.MonthGrid />
  <Calendar.YearGrid />
</Calendar.Root>

parts

partrenderswhat it does
Calendar.Root<div role="group">Takes the options of the Calendar, all but the styling ones: mode, value, bind:value, onChange$, min, max, months, name, autoFocus, locale, labels… Its name is its aria-label (labels.calendar by default) followed by the selection. With name, it adds the hidden inputs.
Calendar.PrevButton, Calendar.NextButton<button>Change the month, a year or twelve years, as the view shows, with the matching label, and aria-disabled at min and max. The icon goes inside.
Calendar.Title<div aria-live="polite">The title of the view: "August 2024", "2024" or "2016 – 2027". It names the grid. Its button shows the months, then the years: button={false} for a title without it, buttonProps for the button. With months, offset is its month.
Calendar.Grid<table role="grid">The keyboard: arrows, Home and End, PageUp and PageDown, Enter and Space. With months, offset is its month, and its GridBody shows that month.
Calendar.GridHead<thead>The weekday names. rowProps and cellProps go to its <tr> and its <th>s.
Calendar.GridBody<tbody>A row per week and a button per day. rowProps, cellProps, dayProps and weekNumberProps go to every <tr>, <td>, day <button> and week number cell.
Calendar.MonthGrid, Calendar.YearGrid<table role="grid">The months of a year and twelve years, only in their view (the days grid, only in its own). rowProps, cellProps and buttonProps. The buttons have data-month or data-year, data-selected, aria-current="date" and disabled.
Calendar.Cell, Calendar.Day<td>, <button>For rows of your own: they keep the attributes of each day, the choice and the keyboard.

styling

Style the days by their attributes, the same ones the styled Calendar uses: data-selected, data-in-range, data-preview, data-unavailable, aria-current="date" and disabled. The whole list is in the API of the Calendar. With Tailwind:

<Calendar.GridBody
  dayProps={{
    class: 'size-9 rounded data-[selected]:bg-black data-[selected]:text-white data-[in-range]:bg-black/5',
  }}
/>

The root has no data-qwik-date, so the stylesheet of a styled Calendar on the same page leaves it alone.

rows of your own

For days with content of your own, a price or a dot for the days with events, render the body yourself. useCalendar() gives the state of the root around, and Calendar.Cell and Calendar.Day keep each day's attributes, the choice and the keyboard. Call it in a component inside the root: Qwik's context only reaches the root's descendants.

SuMoTuWeThFrSa

a dot under the days with events

useCalendar()

It returns signals and QRLs only, so handlers can use it. The value takes the type of the mode: useCalendar<DateRange>().

valueThe selected value, a signal you can write to: the calendar shows the month of a value written from outside.
modeThe mode, as the root got it.
previewThe range a choice of the day under the pointer or the focus would make, while a range has no end, or null.
direction'next' or 'prev' after each move, null before the first one, as the root's data-direction.
monthThe month on show, { year, month }.
view, title'days', 'months' or 'years', and the title of that view.
gridsThe months on show, each with its title and its weeks: { number, days }, with a CalendarDay per day (null for the empty cells): date, label, outside, unavailable, disabled, today, selected, rangeStart, rangeEnd, inRange, preview and tabbable.
monthCells, yearCellsThe cells of the months and the years views: year, month, text, label, disabled, selected, today and tabbable.
today, tabDayToday, and the day where Tab enters the grid.
canGoBack, canGoForwardWhether the view can move, within min and max.
weekdays, labelsThe weekday names in column order, { long, short }, and the texts of the locale.
showWeekNumber, titleIdThe option, and the id of the first title.
select$(day)Chooses a day, as a click on it does. A day that can't be chosen is ignored.
setPreview$(day)Previews the range up to a day, as the pointer on it does: null for none.
prev$(), next$()A month, a year or twelve years away, as the view shows.
setView$(view)What the title does.
chooseMonth$(year, month), chooseYear$(year)What the month and year buttons do.