Datepicker

Material Design 3 datepicker component with single date, date range, and inline calendar support

Datepicker

The Datepicker component allows users to select dates through an intuitive calendar interface. @duskmoon-dev/core provides a complete Material Design 3-inspired datepicker with support for single dates, date ranges, and inline calendars. Uses the native HTML Popover API for dropdown behavior.

Basic Usage

Basic Datepicker

January 2024
Su
Mo
Tu
We
Th
Fr
Sa

Variants

Single Date Selection

The default behavior allows users to select a single date:

Single Date Selection

January 2024
Su
Mo
Tu
We
Th
Fr
Sa

Date Range Selection

For selecting a date range, use the range-specific classes:

Date Range Selection

January 2024
Su
Mo
Tu
We
Th
Fr
Sa

Inline Calendar

Display the calendar inline without a dropdown:

Inline Calendar

January 2024
Su
Mo
Tu
We
Th
Fr
Sa

Color Variants

Secondary Color

Use the secondary theme color:

Secondary Color

January 2024
Su
Mo
Tu
We
Th
Fr
Sa

Tertiary Color

Use the tertiary theme color:

Tertiary Color

January 2024
Su
Mo
Tu
We
Th
Fr
Sa

Special Day States

Today’s Date

Highlight the current date:

Today's Date

Selected Date

Mark a date as selected:

Selected Date

Disabled Date

Disable certain dates:

Disabled Date

Other Month Days

Days from adjacent months:

Other Month Days

Month and Year Picker

Switch between month and year selection views:

Month Picker

Month Picker

2024

Year Picker

Year Picker

2020-2029

Add action buttons to the datepicker footer:

Footer Actions

January 2024
Su
Mo
Tu
We
Th
Fr
Sa

Best Practices

Accessibility

  • Use readonly attribute on the input to prevent manual text entry
  • Provide clear labels for navigation buttons with aria-label
  • Ensure keyboard navigation is supported
  • Mark disabled dates appropriately

Accessibility Example

January 2024
Su
Mo
Tu
We
Th
Fr
Sa

Date Formatting

Display dates in a user-friendly format:

Date Formatting

Range Selection UX

When implementing range selection, provide clear visual feedback:

Range Selection UX

Su
Mo
Tu
We
Th
Fr
Sa

Responsive Design

Ensure the datepicker works well on mobile devices:

Responsive Design

January 2024
Su
Mo
Tu
We
Th
Fr
Sa

Framework Examples

React

import { useState } from 'react';

interface DatepickerProps {
  value?: Date;
  onChange?: (date: Date) => void;
  variant?: 'primary' | 'secondary' | 'tertiary';
  inline?: boolean;
}

export function Datepicker({
  value,
  onChange,
  variant = 'primary',
  inline = false
}: DatepickerProps) {
  const [currentMonth, setCurrentMonth] = useState(new Date());
  const popoverId = `datepicker-${Math.random().toString(36).slice(2)}`;

  const formatDate = (date: Date) => {
    return date.toLocaleDateString('en-US', {
      year: 'numeric',
      month: 'long',
      day: 'numeric'
    });
  };

  return (
    <div className={`datepicker ${variant ? `datepicker-${variant}` : ''}`}>
      {!inline && (
        <div className="datepicker-input-container">
          <input
            type="text"
            className="datepicker-input"
            value={value ? formatDate(value) : ''}
            placeholder="Select date"
            readOnly
          />
          <button className="datepicker-trigger" popoverTarget={popoverId}>
            <span className="datepicker-icon">📅</span>
          </button>
        </div>
      )}
      <div
        id={popoverId}
        className={`datepicker-dropdown ${inline ? 'datepicker-inline' : ''}`}
        popover={inline ? undefined : ''}
      >
        {/* Calendar implementation */}
      </div>
    </div>
  );
}

// Usage
<Datepicker
  value={selectedDate}
  onChange={setSelectedDate}
  variant="primary"
/>

Vue

<template>
  <div :class="['datepicker', variant && `datepicker-${variant}`]">
    <div v-if="!inline" class="datepicker-input-container">
      <input
        type="text"
        class="datepicker-input"
        :value="formattedDate"
        placeholder="Select date"
        readonly
      />
      <button
        class="datepicker-trigger"
        :popovertarget="popoverId"
      >
        <span class="datepicker-icon">📅</span>
      </button>
    </div>
    <div
      :id="popoverId"
      :class="[
        'datepicker-dropdown',
        { 'datepicker-inline': inline }
      ]"
      :popover="inline ? undefined : ''"
    >
      <!-- Calendar implementation -->
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue';

const props = defineProps({
  modelValue: Date,
  variant: {
    type: String,
    default: 'primary'
  },
  inline: {
    type: Boolean,
    default: false
  }
});

const emit = defineEmits(['update:modelValue']);
const popoverId = `datepicker-${Math.random().toString(36).slice(2)}`;

const formattedDate = computed(() => {
  if (!props.modelValue) return '';
  return props.modelValue.toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric'
  });
});
</script>

<!-- Usage -->
<Datepicker
  v-model="selectedDate"
  variant="primary"
/>

API Reference

Class Names

ClassDescription
.datepickerBase datepicker container (required)
.datepicker-input-containerContainer for input and trigger button
.datepicker-triggerIcon button trigger (use with popovertarget)
.datepicker-inputInput field for displaying selected date
.datepicker-iconCalendar icon positioned over input
.datepicker-dropdownCalendar dropdown container (use with popover attribute)
.datepicker-inlineDisplay calendar inline (always visible)
.datepicker-headerCalendar header with navigation
.datepicker-titleMonth/Year title in header
.datepicker-navPrevious/Next navigation buttons
.datepicker-calendarCalendar grid container
.datepicker-weekdayWeekday name header
.datepicker-dayIndividual day cell
.datepicker-day-todayCurrent date highlight
.datepicker-day-selectedSelected date
.datepicker-day-disabledDisabled/unavailable date
.datepicker-day-other-monthDays from adjacent months
.datepicker-day-in-rangeDate within selected range
.datepicker-day-range-startRange start date
.datepicker-day-range-endRange end date
.datepicker-monthsMonth picker grid
.datepicker-monthIndividual month cell
.datepicker-month-selectedSelected month
.datepicker-yearsYear picker grid
.datepicker-yearIndividual year cell
.datepicker-year-selectedSelected year
.datepicker-footerFooter with action buttons
.datepicker-secondaryUse secondary theme color
.datepicker-tertiaryUse tertiary theme color

HTML Structure with Popover API

<div class="datepicker">
  <div class="datepicker-input-container">
    <input type="date" id="my-date" name="my-date" class="datepicker-input">
    <button class="datepicker-trigger" popovertarget="dropdown-id">
      <span class="datepicker-icon">📅</span>
    </button>
  </div>
  <div class="datepicker-dropdown" id="dropdown-id" popover="auto">
    <div class="datepicker-header">
      <button class="datepicker-nav">‹</button>
      <div class="datepicker-title">January 2024</div>
      <button class="datepicker-nav">›</button>
    </div>
    <div class="datepicker-calendar">
      <!-- Weekday headers and day cells -->
    </div>
  </div>
</div>

Combinations

You can combine classes for different effects:

Class Combinations

January 2024
Su
Mo
Tu
We
Th
Fr
Sa
  • Input - Text input fields
  • Button - Action buttons for footer
  • Card - Container for inline calendar

See Also