Custom Components

May 8, 2026 ยท View on GitHub

Use the components prop to extend each rendered HTML element with your own custom components.

Prop NameTypeDescription
componentsCustomComponentsChange the components of the calendar.

You may need to use custom components in advanced applications to:

  • Prevent default events from occurring.
  • Add new event listeners, such as touch events.
  • Display extra content, such as a calendar entry in the day cell.
  • Implement buttons or dropdowns using your own design system components.
  • Wrap an element with another element, like adding a tooltip to a day cell.

Keep accessibility and behavior intact

  • Always forward the props you receive (including aria-*, tabIndex, ref, and event handlers) to preserve keyboard navigation and screen reader support.
  • Reuse classNames and labels from useDayPicker when rendering built-in elements so modifiers and ARIA text remain correct.
  • Prefer composing around the default components instead of rebuilding behavior like focus management in DayButton.

When customizing components, familiarize yourself with the API Reference and the DayPicker Anatomy. Ensure you maintain accessibility.

:::note Custom Components vs Formatters

Custom components allow you to extend DayPicker beyond just using formatters. While formatters modify the content within the calendar, custom components enable you to alter the structure of the HTML elements.

:::

Implementing a Custom Component

  • Pass the components you want to customize to the components prop (see the list of custom components below).
  • Consider reusing the core components and composing your customizations on top of them.
  • Use a custom React Context to share state between your custom components and your application.
<DayPicker
  components={{
    Day: CustomDaycell,
    MonthGrid: CustomMonthGrid,
    // etc.
  }}
/>

Component props cheat sheet

ComponentProps typeNotes
DayDayPropsReceives day (with date) and modifiers.
DayButtonDayButtonPropsHandles focus; keep forwarding ref/aria-*.
NavNavPropsUse provided onPreviousClick/onNextClick.
DropdownDropdownPropsForward aria-label and call onChange with target.
RootRootPropsForward rootRef when animate is enabled.

The components prop accepts a partial map, so pass only the entries you want to override. To customize the month navigation buttons, use NextMonthButton and PreviousMonthButton.

List of Custom Components

NameDescription
CaptionLabelThe caption label of the month grid.
ChevronThe chevron icon used in the navigation buttons and dropdowns.
DayThe day cell in the month grid.
DayButtonThe button containing the day in the day cell.
DropdownThe dropdown element to select years and months.
DropdownNavThe container of the dropdowns.
FooterThe footer element announced by screen readers.
MonthThe container of the MonthGrid.
MonthCaptionThe caption of the month grid.
MonthGridThe grid of days in a month.
MonthsWrapper of the month grids.
MonthsDropdownThe dropdown with the months.
NavThe navigation element with the next and previous buttons.
NextMonthButtonThe next month button element in the navigation.
OptionThe <option> HTML element in the dropdown.
PreviousMonthButtonThe previous month button element in the navigation.
RootThe root element of the calendar.
SelectThe select element in the dropdowns.
WeekThe week rows.
WeekNumberThe cell with the number of the week.
WeekNumberHeaderThe header of the week number column.
WeekdayThe weekday name in the header.
WeekdaysThe row containing the week days.
WeeksThe weeks section in the month grid.
YearsDropdownThe dropdown with the years.

DayPicker Hook

In a custom component, import the useDayPicker hook to access the DayPicker context.

import { useDayPicker } from "@daypicker/react";
FunctionReturn valueDescription
useDayPickerDayPickerContextReturns the current state of DayPicker and functions to navigate the calendar.

DayPicker Context

The DayPicker context provides the current state of the calendar, including the selected days, modifiers, and navigation state.

NameTypeDescription
classNamesClassNamesThe class names for the UI elements.
componentsCustomComponentsThe components used internally by DayPicker.
formattersFormattersThe formatters used to format the UI elements.
getModifiers(day) => ModifiersReturns the modifiers for the given day.
goToMonth(month) => voidNavigates to the specified month.
isSelected(date) => boolean | undefinedWhether the given date is selected.
labelsLabelsThe labels used in the user interface.
monthsCalendarMonth[]The months displayed in the calendar.
nextMonthDate | undefinedThe next month to display.
previousMonthDate | undefinedThe previous month to display.
selectSelectHandler<T> | undefinedSets a selection.
selectedSelectedValue<T> | undefinedThe selected date(s).
stylesPartial<Styles> | undefinedThe styles for the UI elements.
dayPickerPropsDayPickerPropsThe props passed to the DayPicker component.

Examples

Intercepting Click Events

For example, you can use a custom DayButton to select days with a double-click event. This approach uses a custom React context to share the selected date state between the custom DayButton and the main component.

import React from "react";

import { DayButton, type DayButtonProps, DayPicker } from "@daypicker/react";

// Create a context to share the selected date state between the custom DayButton and the main component.
const SelectedDateContext = React.createContext<{
  selected?: Date;
  setSelected?: React.Dispatch<React.SetStateAction<Date | undefined>>;
}>({});

// Custom DayButton that uses the context to set the selected date on double-click and clear it on single click.
function DayButtonWithContext(props: DayButtonProps) {
  const { day, modifiers, ...buttonProps } = props;

  const { setSelected } = React.use(SelectedDateContext);
  return (
    <DayButton
      {...buttonProps}
      day={day}
      modifiers={modifiers}
      onClick={() => setSelected?.(undefined)}
      onDoubleClick={() => setSelected?.(day.date)}
    />
  );
}

export function MyDatePicker() {
  const [selected, setSelected] = React.useState<Date>();

  return (
    <SelectedDateContext.Provider value={{ selected, setSelected }}>
      <DayPicker
        mode="single"
        selected={selected}
        onSelect={setSelected}
        components={{
          DayButton: DayButtonWithContext,
        }}
      />
    </SelectedDateContext.Provider>
  );
}

Compose with the defaults

When you want to add UI but keep the built-in behavior (focus, labels, modifier classes), wrap the default component from context.

import { type DayButtonProps, DayButton, DayPicker, UI, useDayPicker } from "@daypicker/react";

function WrappedDayButton(props: DayButtonProps) {
  const { classNames } = useDayPicker();
  return (
    <DayButton
      {...props}
      className={`${classNames[UI.DayButton]} my-custom-class`}
    >
      <span>{props.day.date.getDate()}</span>
      <small aria-hidden>โ˜…</small>
    </DayButton>
  );
}

export function WrappedDayExample() {
  return <DayPicker components={{ DayButton: WrappedDayButton }} />;
}

Custom Select Dropdown

You can use a custom Dropdown to select years and months. The example below uses a simplified version of shadcn/ui's Select.

import React, { useState } from "react";

import { DayPicker, type DropdownProps } from "@daypicker/react";

import {
  Select,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";

export function CustomSelectDropdown(props: DropdownProps) {
  const { options, value, onChange, "aria-label": ariaLabel } = props;

  const handleValueChange = (newValue: string) => {
    if (onChange) {
      const syntheticEvent = {
        target: {
          value: newValue,
        },
      } as React.ChangeEvent<HTMLSelectElement>;

      onChange(syntheticEvent);
    }
  };

  return (
    <Select value={value?.toString()} onValueChange={handleValueChange}>
      <SelectTrigger aria-label={ariaLabel}>
        <SelectValue />
      </SelectTrigger>
      <SelectContent>
        <SelectGroup>
          {options?.map((option) => (
            <SelectItem
              key={option.value}
              value={option.value.toString()}
              disabled={option.disabled}
            >
              {option.label}
            </SelectItem>
          ))}
        </SelectGroup>
      </SelectContent>
    </Select>
  );
}

export function CustomDropdown() {
  const [selected, setSelected] = useState<Date | undefined>();

  return (
    <DayPicker
      captionLayout="dropdown"
      components={{ Dropdown: CustomSelectDropdown }}
      mode="single"
      selected={selected}
      onSelect={setSelected}
      footer={
        selected ? `Selected: ${selected.toLocaleDateString()}` : "Pick a day."
      }
    />
  );
}

If your design system portals dropdown content, provide the container (as shown in examples/CustomDropdown/CustomDropdown.tsx) so the list renders inside the calendar's shadow root in the docs.

Structural customization

Swap layout components to add design-system wrappers or decoration while keeping behavior.

import { DayPicker, type RootProps } from "@daypicker/react";

function CardRoot(props: RootProps) {
  const { rootRef, ...rest } = props;
  return (
    <div ref={rootRef} className="card shadow-md" {...rest}>
      {rest.children}
    </div>
  );
}

export function CustomRootExample() {
  return <DayPicker components={{ Root: CardRoot }} />;
}

Choosing Day vs. DayButton vs. formatters

  • Use DayButton to change interactivity or add content inside the button while keeping the cell layout.
  • Use Day to change the table cell structure (wrappers, tooltips) when you need control over the <td>.
  • Use formatters for simple text changes (e.g., labels) without altering structure.

What are you using custom components for? Let us know.