@htmlbricks/hb-calendar-appointments
v0.76.5
Published
Month agenda view: events for the current month are grouped by calendar day and listed chronologically with weekday, day number, time, and colored markers. Optional header with month navigation; changing month or selecting a day dispatches `changeCalendar
Readme
hb-calendar-appointments
Category: calendar · Tags: calendar, appointments
Summary
A month agenda web component: it shows only events in the visible month, grouped by calendar day, with per-day headings and clickable rows for each appointment. An optional header switches the month and exposes slots for labels and navigation chrome.
What it does
- Filters
eventsto the month implied bydate(month + year). - Sorts events by
datewheneventsis parsed from a string. - Renders one block per day that has at least one event: weekday (long, locale from
navigator.languages[0]oren), day-of-month number, then rows ordered as in the sorted list. - Each row shows a Bootstrap Icons dot (
bi-dot), time (HH:mm), andlabel; optional per-eventcoloroverrides the icon color via inline style. - Month navigation (
disable_headeroff) updatesdateand emitschangeCalendarDate. - Row click emits
calendarEventClickwith the eventid.
The date-holidays package is imported and an IT instance is constructed in script, but that object is not used anywhere in the template or derived data (no holiday-based labels or filtering in the current implementation).
UI / layout
| Region | Behavior |
|--------|------------|
| Header (optional) | Flex row: default title (month name + year via Intl + dayjs), prev/next controls. Wrapped in part="calendar-header". Inner title span uses part="calendar-current-time-header". Entire header hidden when disable_header is enabled (see logic below). |
| Slots in header | header wraps title + nav; calendar_month replaces default month/year text; header_month_icon_prev / header_month_icon_next replace default buttons (still wired to changeMonth(-1) / changeMonth(1) via outer onclick). |
| Agenda list | Under #appointments_container: for each day bucket, a bold day line (events_day) then event_row blocks (focusable role="button"). If the month has no events, the list area is empty (no placeholder). |
Icons are loaded for the shadow tree via styles/webcomponent.scss (Bootstrap Icons font). A <svelte:head> stylesheet link is also present but does not apply inside shadow DOM by itself.
Logic
- Visible month:
month/yearderived fromdate(dayjs). - Filtering:
monthsEventkeeps events whose month and year matchdate. - Grouping:
eventsOfThisMonthByDaybuckets by day-of-month (D); first occurrence of a day creates the bucket, further events append to that bucket’s array. disable_header: In$effect, string values are normalized:true/yes/""(empty) → header hidden; otherwise shown.events: If a string,JSON.parse; then sorted ascending bynew Date(a.date)vsnew Date(b.date).selected: If a string, parsed withdayjs(selected).toDate()for in-component use. There is aselectDayhelper that setsselectedand would emitchangeSelectedDate, but nothing in the default markup callsselectDay, so that event is not produced by the shipped UI (only the typed API / future wiring).
Custom element
hb-calendar-appointmentsAttributes / properties
HTML attributes are strings. Align with your bridge; the component’s $effect coerces some values.
| Name | Typing (Component) | Notes |
|------|----------------------|--------|
| id | string (optional) | Passed through like other props; host id if set as attribute. |
| date | Date (optional) | Default: start of current month (dayjs().startOf("month")). Drives which month’s events are shown. From HTML, use an ISO-like string your runtime parses to Date / or set the property in JS. |
| events | IEvent[] (optional) | JSON array string from attributes; each item: date, label, id required for useful rows; link, icon, color optional (link / icon are not read by the template). |
| selected | Date (optional) | Parsed from string in $effect. No built-in control updates selection or emits changeSelectedDate. |
| disable_header | boolean (optional) | Default false. For attributes, this codebase often uses yes / no; the effect also treats string "true", "yes", and "" as hide header. |
IEvent (from typings)
| Field | Type | Used in UI |
|-------|------|------------|
| date | Date | Filter, sort, time column, weekday/day grouping |
| label | string | Row text (aria-label, visible label) |
| id | string | calendarEventClick payload |
| link | optional string | No |
| icon | optional string | No |
| color | optional string | Icon color (inline style) |
Events (CustomEvent)
| Name | detail | When emitted (current implementation) |
|------|-----------|----------------------------------------|
| calendarEventClick | { eventId: string } | User activates an .event_row (click path in template). |
| changeCalendarDate | { date: Date } | Prev/next month navigation runs changeMonth. |
| changeSelectedDate | { selectedDate: Date } | Only if something called selectDay — not wired in the default Svelte markup. |
Styling
CSS custom properties
Documented in extra/docs.ts; defaults from code (styles/webcomponent.scss + descriptions in docs):
| Variable | Kind | Default / source | Role |
|----------|------|-------------------|------|
| --hb-calendar-event-button-color | color | var(--bulma-link, #485fc7) on :host | Dot icon color when event.color is not set. |
| --bulma-radius | size | theme / 0.25rem fallback in SCSS | border-radius on .event_row. |
| --bulma-border | color | theme / hsl(0deg 0% 86%) fallback | outline on .event_row:hover. |
CSS parts (::part)
| Part | Description |
|------|-------------|
| calendar-header | Outer header strip (month navigation + title area). |
| calendar-current-time-header | Inner title span (month slot + default month/year text). |
Slots
| Slot | Description |
|------|-------------|
| header_month_icon_prev | Replace default “previous month” control (e.g. icon button). |
| header_month_icon_next | Replace default “next month” control. |
| header | Wraps the whole header row (title + nav); default fills month + controls. |
| calendar_month | Replace/wrap visible month/year label in the header row. |
Typings
Authoring types live in types/webcomponent.type.d.ts:
Component—id,date,events,selected,disable_headerIEvent— event record shapeEvents—calendarEventClick,changeCalendarDate,changeSelectedDate
Built outputs (types/html-elements.d.ts, types/svelte-elements.d.ts) are regenerated with npm run build:wc.
Example HTML
<hb-calendar-appointments
id="agenda-1"
disable_header="no"
date="2026-04-01T00:00:00.000Z"
events='[
{"id":"a1","label":"Stand-up","date":"2026-04-17T09:00:00.000Z"},
{"id":"a2","label":"Review","date":"2026-04-17T15:30:00.000Z","color":"#b86bff"}
]'
></hb-calendar-appointments>With hidden header:
<hb-calendar-appointments
disable_header="yes"
events='[{"id":"1","label":"Meeting","date":"2026-03-15T10:00:00.000Z"}]'
></hb-calendar-appointments>Listen in JavaScript, for example:
document.querySelector("hb-calendar-appointments")?.addEventListener("calendarEventClick", (e) => {
console.log(e.detail.eventId);
});
document.querySelector("hb-calendar-appointments")?.addEventListener("changeCalendarDate", (e) => {
console.log(e.detail.date);
});