heroui-inc/heroui · error · Error

useCalendarOrRangeState must be used within a <Calendar> or

Error message

useCalendarOrRangeState must be used within a <Calendar> or <RangeCalendar> component.

What it means

useCalendarOrRangeState is an internal-ish hook used by CalendarYearPicker parts. It reads both the CalendarStateContext and RangeCalendarStateContext; if neither provider is found (i.e., the hook is called outside a <Calendar> or <RangeCalendar> subtree), it throws immediately. The library throws because the year picker depends on the parent calendar's state (focused date, selection) to function.

Source

Thrown at packages/react/src/components/calendar-year-picker/use-calendar-state.ts:17

"use client";

import {use} from "react";
import {CalendarStateContext} from "react-aria-components/Calendar";
import {RangeCalendarStateContext} from "react-aria-components/RangeCalendar";

/**
 * Returns the active Calendar or RangeCalendar state from RAC context.
 * Must be used inside <Calendar> or <RangeCalendar>.
 */
function useCalendarOrRangeState() {
  const calendarState = use(CalendarStateContext);
  const rangeCalendarState = use(RangeCalendarStateContext);
  const state = calendarState ?? rangeCalendarState;

  if (!state) {
    throw new Error(
      "useCalendarOrRangeState must be used within a <Calendar> or <RangeCalendar> component.",
    );
  }

  return state;
}

export {useCalendarOrRangeState};

View on GitHub (pinned to 7546fff813)

Solutions

  1. Move the component using this hook inside <Calendar>...</Calendar> or <RangeCalendar>...</RangeCalendar> so the context provider is an ancestor
  2. If you only need the year picker UI, compose it as <Calendar><CalendarYearPicker.Trigger/><CalendarYearPicker.Grid/></Calendar> instead of standalone parts
  3. If rendering in a portal or separate root, ensure the calendar context provider wraps that root, or pass state via props instead of context
  4. Check that you haven't destructured the compound component incorrectly (e.g., using internals like useCalendarOrRangeState directly)

Example fix

// before
<CalendarYearPicker.Grid /> // rendered standalone

// after
<Calendar>
  <Calendar.YearPicker />
</Calendar>
Defensive patterns

Strategy: validation

Validate before calling

import {Calendar, RangeCalendar} from "@heroui/react";
// Ensure the consumer is a descendant:
// <Calendar> or <RangeCalendar> must wrap the component using calendar state.

Type guard

// Not runtime-checkable generically; structurally, only use calendar internals
// inside components rendered as children of <Calendar>/<RangeCalendar>.
const isInsideCalendar = (el: HTMLElement | null) =>
  !!el?.closest('[data-slot]'); // adjust to the calendar's data-slot value

Prevention

When it happens

Trigger: Calling useCalendarOrRangeState() (or rendering a CalendarYearPicker part that uses it, e.g. CalendarYearPicker.Grid or Trigger) outside of a <Calendar> or <RangeCalendar> component tree; or rendering such parts in a portal/separate React root that is not a descendant of the calendar provider.

Common situations: Building a standalone year-picker, copying CalendarYearPicker internals into a custom component, extracting a sub-part into its own file and rendering it in isolation in a story/test, or accidental usage outside the compound component hierarchy.

Related errors


AI-assisted analysis of heroui-inc/heroui@7546fff813 (2026-08-28). Data as JSON: /api/errors/8ff3a62223ceee99. Report an issue: GitHub.