Calendar

Component

Interactive examples and API documentation

Basic
A basic calendar component with Year/Month switch.
2026
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
July
January
February
March
April
May
June
July
August
September
October
November
December
Su Mo Tu We Th Fr Sa
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
Code
<%= render HakumiComponents::Calendar::Component.new %>
Notice Calendar
This component can be rendered by using date_cell_render with the data you need.
2026
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
July
January
February
March
April
May
June
July
August
September
October
November
December
Su Mo Tu We Th Fr Sa
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
This is warning event.
This is usual event.
13
14
15
16
17
This is warning event.
This is usual event.
This is error event.
18
19
20
21
22
This is warning event.
This is very long usual event......
23
24
25
26
27
This is error event 1.
This is error event 2.
This is error event 3.
This is error event 4.
28
29
30
31
1
Code
<%
  events = {
    Date.today => [
      { id: 1, type: :warning, content: "This is warning event." },
      { id: 2, type: :success, content: "This is usual event." }
    ],
    Date.today + 5 => [
      { id: 3, type: :warning, content: "This is warning event." },
      { id: 4, type: :success, content: "This is usual event." },
      { id: 5, type: :error, content: "This is error event." }
    ],
    Date.today + 10 => [
      { id: 6, type: :warning, content: "This is warning event." },
      { id: 7, type: :success, content: "This is very long usual event......" }
    ],
    Date.today + 15 => [
      { id: 8, type: :error, content: "This is error event 1." },
      { id: 9, type: :error, content: "This is error event 2." },
      { id: 10, type: :error, content: "This is error event 3." },
      { id: 11, type: :error, content: "This is error event 4." }
    ]
  }
%>

<%= render HakumiComponents::Calendar::Component.new(events: events, id: "notice-calendar") %>

<script>
  (() => {
    const calendarEl = document.getElementById("notice-calendar")
    if (!calendarEl) return

    let wired = false
    const wire = () => {
      if (wired) return true
      
      const api = calendarEl.hakumiComponent?.api
      if (!api) return false

      calendarEl.addEventListener("hakumi--calendar:select", (e) => {
        const date = e.detail.date
        const dateStr = date.toISOString().split("T")[0]
        const events = api.getEventsForDate(dateStr)
        
        console.log("📅 Selected date:", dateStr)
        console.log("📋 Events for this date:", events)
        
        if (events.length > 0) {
          console.table(events)
        }
      })

      console.log("🗓️ Calendar wired! All events:", api.getEvents())

      wired = true
      return true
    }

    if (wire()) return
    const interval = setInterval(() => { if (wire()) clearInterval(interval) }, 50)
    setTimeout(() => clearInterval(interval), 5000)
  })()
</script>
Card
Nested inside a container element for rendering in limited space.
2026
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
July
January
February
March
April
May
June
July
August
September
October
November
December
Su Mo Tu We Th Fr Sa
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
Code
<%= render HakumiComponents::Calendar::Component.new(fullscreen: false) %>
Selectable Calendar
A basic calendar component with Year/Month switch. Listen to the select event to get the selected date.
2026
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
July
January
February
March
April
May
June
July
August
September
October
November
December
Su Mo Tu We Th Fr Sa
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
Code
<%= render HakumiComponents::Calendar::Component.new(
  value: Date.today,
  id: "selectable-calendar"
) %>

<div style="margin-top: 16px;">
  <%= render HakumiComponents::Alert::Component.new(
    type: :info,
    message: "Selected date will be shown here",
    id: "selected-date-alert"
  ) %>
</div>

<script>
  (() => {
    const calendarEl = document.getElementById("selectable-calendar")
    const alertEl = document.getElementById("selected-date-alert")
    if (!calendarEl || !alertEl) return

    let wired = false
    const wire = () => {
      if (wired) return true
      
      const calendarApi = calendarEl.hakumiComponent?.api
      const alertApi = alertEl.hakumiComponent?.api
      if (!calendarApi || !alertApi) return false

      calendarEl.addEventListener("hakumi--calendar:select", (e) => {
        const date = e.detail.date
        const formatted = date.toLocaleDateString("en-US", {
          weekday: "long",
          year: "numeric",
          month: "long",
          day: "numeric"
        })
        alertApi.setMessage(`You selected: ${formatted}`)
      })

      wired = true
      return true
    }

    if (wire()) return
    const interval = setInterval(() => { if (wire()) clearInterval(interval) }, 50)
    setTimeout(() => clearInterval(interval), 5000)
  })()
</script>
Show Week
Show week number in fullscreen calendar by setting show_week prop to true.
2026
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
July
January
February
March
April
May
June
July
August
September
October
November
December
Su Mo Tu We Th Fr Sa
27
28
29
30
1
2
3
4
28
5
6
7
8
9
10
11
29
12
13
14
15
16
17
18
30
19
20
21
22
23
24
25
31
26
27
28
29
30
31
1
Code
<%= render HakumiComponents::Calendar::Component.new(show_week: true) %>
Customize Header
Customize Calendar header content using the with_header_content slot.
Custom Header
Su Mo Tu We Th Fr Sa
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
Code
<%= render HakumiComponents::Calendar::Component.new(
  fullscreen: false,
  id: "custom-header-calendar"
) do |calendar|
  calendar.with_header_content do %>
    <div style="display: flex; align-items: center; justify-content: space-between; width: 100%;">
      <div style="display: flex; align-items: center; gap: 8px;">
        <%= render HakumiComponents::Button::Component.new(
          type: :text,
          size: :small,
          id: "cal-prev-year",
          icon: :double_left
        ) %>
        <%= render HakumiComponents::Button::Component.new(
          type: :text,
          size: :small,
          id: "cal-prev-month",
          icon: :left
        ) %>
      </div>

      <div id="cal-header-title" style="font-weight: 500;">
        Custom Header
      </div>

      <div style="display: flex; align-items: center; gap: 8px;">
        <%= render HakumiComponents::Button::Component.new(
          type: :text,
          size: :small,
          id: "cal-next-month",
          icon: :right
        ) %>
        <%= render HakumiComponents::Button::Component.new(
          type: :text,
          size: :small,
          id: "cal-next-year",
          icon: :double_right
        ) %>
      </div>
    </div>
  <% end %>
<% end %>

<script>
  (() => {
    const calendarEl = document.getElementById("custom-header-calendar")
    if (!calendarEl) return

    let wired = false
    const wire = () => {
      if (wired) return true
      
      const api = calendarEl.hakumiComponent?.api
      if (!api) return false

      const getTitleEl = () => document.getElementById("cal-header-title")

      const updateTitle = () => {
        const date = api.getValue()
        const monthNames = ["January", "February", "March", "April", "May", "June",
                           "July", "August", "September", "October", "November", "December"]
        const title = getTitleEl()
        if (title) {
          title.textContent = `${monthNames[date.getMonth()]} ${date.getFullYear()}`
        }
      }

      let detachControls = () => {}
      const attachControls = () => {
        detachControls()

        const removers = []
        const bindControl = (id, handler) => {
          const el = document.getElementById(id)
          if (!el) return
          const wrapped = (event) => {
            event.preventDefault()
            handler()
          }
          el.addEventListener("click", wrapped)
          removers.push(() => el.removeEventListener("click", wrapped))
        }

        bindControl("cal-prev-year", () => api.prevYear())
        bindControl("cal-prev-month", () => api.prevMonth())
        bindControl("cal-next-month", () => api.nextMonth())
        bindControl("cal-next-year", () => api.nextYear())

        detachControls = () => removers.forEach((off) => off())
      }

      calendarEl.addEventListener("hakumi--calendar:change", () => {
        updateTitle()
        attachControls()
      })

      attachControls()
      updateTitle()
      wired = true
      return true
    }

    if (wire()) return
    const interval = setInterval(() => { if (wire()) clearInterval(interval) }, 50)
    setTimeout(() => clearInterval(interval), 5000)
  })()
</script>

Calendar API

Prop Type Default Description
value Date or String nil The current selected date (defaults to Date.today for display if not provided)
default_value Date or String nil The initial date when first rendered
mode Symbol :month The display mode of the calendar
fullscreen Boolean true Whether to display in fullscreen mode
show_week Boolean false Whether to show week number column
locale :en or :es :en The locale for day/month names
valid_range [Date, Date] - Range of valid selectable dates
year_range Range or Array nil Years to show in year selector (defaults to ±10 years from current). E.g., 2020..2030 or [2020, 2021, 2022]
events Hash {} Events to display on dates. Format: { Date => [{ type: :success/:warning/:error, content: 'text
date_cell_render Proc - Custom render function for date cells. Receives date as argument. Overrides events prop.
month_cell_render Proc - Custom render function for month cells. Receives month number as argument.
header_render Proc or false - Custom header render function, or false to hide header
disabled_date Proc - Function to determine if a date is disabled. Receives date as argument.
static Boolean auto Prevent client-side re-rendering. Auto-enabled when using date_cell_render/month_cell_render.

JavaScript API

Access via element.hakumiComponent.api or HakumiComponents.get(element.id).
Prop Type Default Description
getValue() Method - Return a Date for the first day of the current display month.
getSelectedDate() Method - Return the selected date, or null when no date is selected.
setValue(date) Method - Set the selected Date. Pass { navigate: true } as the second argument to update the displayed month/year.
clearSelection() Method - Clear the selected date and refresh the calendar body.
getMode() Method - Return the current display mode.
setMode(mode) Method - Set the display mode to month or year.
goToToday() Method - Navigate the display to the current month.
nextMonth() Method - Navigate the display to the next month.
prevMonth() Method - Navigate the display to the previous month.
nextYear() Method - Navigate the display to the next year.
prevYear() Method - Navigate the display to the previous year.
nextDecade() Method - Navigate the display forward ten years.
prevDecade() Method - Navigate the display back ten years.
refresh() Method - Re-render the current calendar body.
getEvents() Method - Return a shallow copy of the calendar event map.
setEvents(events) Method - Replace the calendar event map and refresh dynamic calendars.
addEvent(date, event) Method - Add an event object to a date.
updateEvent(id, updates) Method - Update the event with the matching id.
removeEvent(date, indexOrId) Method - Remove all events for a date, or remove an event by index for that date.
removeEventById(id) Method - Remove the event with the matching id.
getEventById(id) Method - Return the matching event with its date, or null when missing.
getEventsForDate(date) Method - Return the event array for a date.
clearEvents() Method - Remove all calendar events and refresh dynamic calendars.
setRange(startDate, endDate, hoveredDate) Method - Set the highlighted range and optional hovered date.
clearRange() Method - Clear the highlighted range state.
getRange() Method - Return the current range date keys.
setHoveredDate(date) Method - Set or clear the currently hovered range date.