Skip to main content

Week Numbers

Display ISO week numbers alongside calendar dates for business and planning applications.

Enabling Week Numbers

picker.showWeekNumber = true;
import { html } from 'lit';

const template = html`
  <app-date-picker
    .showWeekNumber=${true}
    weekNumberType="first-4-day-week"
  ></app-date-picker>
`;

Week Number Types

The component supports different week numbering systems:
TypeDescriptionRegion
first-4-day-weekISO 8601 (default)International standard, Europe
first-day-of-yearWeek 1 starts January 1stNorth America
first-full-weekFirst complete weekAlternative system
// ISO 8601 (most common)
picker.weekNumberType = 'first-4-day-week';

// North American convention
picker.weekNumberType = 'first-day-of-year';

// First full week
picker.weekNumberType = 'first-full-week';
The first-4-day-week type follows ISO 8601, where week 1 is the first week with at least 4 days in the new year.
From src/mixins/date-picker-mixin.ts:39:
@property({ converter: { toAttribute: nullishAttributeConverter }, reflect: true }) 
public weekNumberType: WeekNumberType = 'first-4-day-week';

Customizing Week Number Labels

picker.weekLabel = 'Week';              // Full label
picker.shortWeekLabel = 'Wk';           // Abbreviated label
picker.weekNumberTemplate = 'Week %s';  // Template for tooltips
From src/constants.ts:12-15:
export const labelShortWeek = 'Wk' as const;
export const labelWeek = 'Week' as const;
export const weekNumberTemplate = 'Week %s' as const;
Example with custom labels:
import { html } from 'lit';

// German week numbers
const germanWeeks = html`
  <app-date-picker
    .showWeekNumber=${true}
    locale="de-DE"
    weekLabel="Woche"
    shortWeekLabel="KW"
    weekNumberTemplate="Woche %s"
  ></app-date-picker>
`;

Disabled Dates

Prevent selection of specific dates (holidays, blackout dates, unavailable dates).

Single and Multiple Dates

// Disable single date
picker.disabledDates = '2024-12-25';

// Disable multiple dates (comma-separated)
picker.disabledDates = '2024-12-24,2024-12-25,2024-12-26';

// Disable multiple dates (with spaces)
picker.disabledDates = '2024-01-01, 2024-07-04, 2024-11-28';
From src/date-picker/date-picker.ts:126-127:
disabledDates: splitString(disabledDates, toResolvedDate),
The splitString helper splits the comma-separated string and converts each value using toResolvedDate.

Using with Template Literals

import { LitElement, html } from 'lit';
import { customElement, state } from 'lit/decorators.js';

@customElement('booking-calendar')
export class BookingCalendar extends LitElement {
  @state()
  private holidays = [
    '2024-01-01', // New Year
    '2024-07-04', // Independence Day
    '2024-12-25', // Christmas
  ];

  render() {
    return html`
      <app-date-picker
        .disabledDates=${this.holidays.join(',')}
      ></app-date-picker>
    `;
  }
}

Dynamic Disabled Dates

import { LitElement, html } from 'lit';
import { customElement, state } from 'lit/decorators.js';

@customElement('dynamic-disabled-dates')
export class DynamicDisabledDates extends LitElement {
  @state()
  private bookedDates: string[] = [];

  async connectedCallback() {
    super.connectedCallback();
    // Fetch booked dates from API
    const response = await fetch('/api/booked-dates');
    this.bookedDates = await response.json();
  }

  render() {
    return html`
      <app-date-picker
        .disabledDates=${this.bookedDates.join(',')}
        min="2024-01-01"
        max="2024-12-31"
      ></app-date-picker>
    `;
  }
}

Disabled Days of Week

Disable specific days of the week (e.g., weekends, specific business days).

Basic Usage

// Disable Sundays (0)
picker.disabledDays = '0';

// Disable weekends (Saturday=6, Sunday=0)
picker.disabledDays = '0,6';

// Disable Monday and Friday (1,5)
picker.disabledDays = '1,5';
Day numbers follow JavaScript’s Date.getDay() convention: 0 = Sunday, 1 = Monday, …, 6 = Saturday.

Common Patterns

// Disable Saturdays and Sundays
picker.disabledDays = '0,6';
From src/date-picker/date-picker.ts:127-128:
disabledDays: splitString(disabledDays, Number),
The splitString helper converts comma-separated day numbers to an array of numbers.

Date Range Constraints

Limit selectable dates to a specific range using min and max properties.

Basic Range

picker.min = '2024-01-01';
picker.max = '2024-12-31';

Dynamic Ranges

import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';

@customElement('date-range-picker')
export class DateRangePicker extends LitElement {
  private getToday(): string {
    return new Date().toISOString().split('T')[0];
  }

  private getMaxDate(): string {
    const date = new Date();
    date.setDate(date.getDate() + 30);
    return date.toISOString().split('T')[0];
  }

  render() {
    return html`
      <!-- Only allow next 30 days -->
      <app-date-picker
        .min=${this.getToday()}
        .max=${this.getMaxDate()}
      ></app-date-picker>
    `;
  }
}

Default Range Values

From src/constants.ts:16 and src/date-picker/date-picker.ts:256-257:
export const MAX_DATE = toResolvedDate('2100-12-31');

// In DatePicker constructor:
this._min = new Date(todayDate);
this._max = new Date(MAX_DATE);
If min or max is set to a falsy value, it will be overridden with the default. The default min is today’s date, and the default max is December 31, 2100.

Combining Constraints

import { html } from 'lit';

// Business days only, within next 60 days, excluding holidays
const businessPicker = html`
  <app-date-picker
    .min=${getTodayString()}
    .max=${getFutureDateString(60)}
    disabledDays="0,6"
    disabledDates="2024-07-04,2024-11-28,2024-12-25"
  ></app-date-picker>
`;

function getTodayString(): string {
  return new Date().toISOString().split('T')[0];
}

function getFutureDateString(days: number): string {
  const date = new Date();
  date.setDate(date.getDate() + days);
  return date.toISOString().split('T')[0];
}

Start View Configuration

Control which view the calendar opens to:
// Start with calendar view (default)
picker.startView = 'calendar';

// Start with year selection
picker.startView = 'yearGrid';
From src/constants.ts:22:
export const startViews = ['calendar', 'yearGrid'] as const;

Use Cases

// Start with year selection for birth dates
const birthDatePicker = html`
  <app-date-picker
    startView="yearGrid"
    min="1920-01-01"
    max="2010-12-31"
  ></app-date-picker>
`;

View Switching

Users can switch between views by clicking the year/month dropdown button:
From src/date-picker/date-picker.ts:223-225:
#updateStartView = (): void => {
  this.startView = this.startView === 'yearGrid' ? 'calendar' : 'yearGrid';
};

Value Clamping

When setting a value outside the min/max range, it’s automatically clamped:
picker.min = '2024-01-01';
picker.max = '2024-12-31';

// Value is clamped to 2024-01-01
picker.value = '2023-06-15';

// Value is clamped to 2024-12-31
picker.value = '2025-06-15';
From src/date-picker/date-picker.ts:419-421:
const valueDate = toResolvedDate(
  clampValue(+newMin.date, +newMax.date, +newValue.date)
);
Navigation buttons are automatically hidden when at min/max boundaries:
From src/date-picker/date-picker.ts:314-315:
${this.#renderNavigationButton('previous', isInCurrentMonth(_min, _currentDate))}
${this.#renderNavigationButton('next', isInCurrentMonth(_max, _currentDate))}

Complete Advanced Example

Here’s a complete example combining multiple advanced features:
import { LitElement, html, css } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import 'app-datepicker/dist/date-picker/app-date-picker.js';

@customElement('advanced-booking-calendar')
export class AdvancedBookingCalendar extends LitElement {
  static styles = css`
    :host {
      display: block;
      padding: 24px;
    }

    .calendar-container {
      max-width: 320px;
      margin: 0 auto;
    }

    .info {
      margin-top: 16px;
      padding: 12px;
      background: #f5f5f5;
      border-radius: 4px;
    }

    app-date-picker {
      --app-primary: #2563eb;
      --app-on-primary: #ffffff;
    }
  `;

  @state()
  private selectedDate = '';

  @state()
  private bookedDates: string[] = [];

  // Company holidays
  private holidays = [
    '2024-01-01', // New Year's Day
    '2024-07-04', // Independence Day
    '2024-11-28', // Thanksgiving
    '2024-12-25', // Christmas
  ];

  async connectedCallback() {
    super.connectedCallback();
    await this.loadBookedDates();
  }

  async loadBookedDates() {
    // Simulate API call
    await new Promise(resolve => setTimeout(resolve, 1000));
    this.bookedDates = [
      '2024-03-20',
      '2024-03-21',
      '2024-03-27',
    ];
  }

  get allDisabledDates(): string {
    return [...this.holidays, ...this.bookedDates].join(',');
  }

  getTodayString(): string {
    return new Date().toISOString().split('T')[0];
  }

  getMaxDateString(): string {
    // Allow booking up to 90 days in advance
    const date = new Date();
    date.setDate(date.getDate() + 90);
    return date.toISOString().split('T')[0];
  }

  handleDateUpdate(event: CustomEvent) {
    this.selectedDate = event.detail.value;
  }

  render() {
    return html`
      <div class="calendar-container">
        <h2>Book an Appointment</h2>
        
        <app-date-picker
          .min=${this.getTodayString()}
          .max=${this.getMaxDateString()}
          .disabledDates=${this.allDisabledDates}
          disabledDays="0,6"
          .showWeekNumber=${true}
          weekNumberType="first-4-day-week"
          locale="en-US"
          .firstDayOfWeek=${1}
          @date-updated=${this.handleDateUpdate}
        ></app-date-picker>

        ${this.selectedDate ? html`
          <div class="info">
            <strong>Selected Date:</strong><br>
            ${new Date(this.selectedDate).toLocaleDateString('en-US', {
              weekday: 'long',
              year: 'numeric',
              month: 'long',
              day: 'numeric'
            })}
          </div>
        ` : html`
          <div class="info">
            <strong>Booking Rules:</strong>
            <ul>
              <li>Weekdays only (Mon-Fri)</li>
              <li>Up to 90 days in advance</li>
              <li>Excludes holidays and booked dates</li>
            </ul>
          </div>
        `}
      </div>
    `;
  }
}

Keyboard Navigation

The component supports full keyboard navigation:
KeyAction
Arrow KeysNavigate between dates
HomeJump to first day of week
EndJump to last day of week
Page UpPrevious month
Page DownNext month
Enter / SpaceSelect focused date
EscapeClose picker (input variant)
TabMove focus through elements
From src/constants.ts:17-21:
export const navigationKeyListNext = [keyArrowDown, keyPageDown, keyEnd];
export const navigationKeyListPrevious = [keyArrowUp, keyPageUp, keyHome];
export const navigationKeySetDayNext = new Set([...navigationKeyListNext, keyArrowRight]);
export const navigationKeySetDayPrevious = new Set([...navigationKeyListPrevious, keyArrowLeft]);
export const navigationKeySetGrid = new Set([...navigationKeySetDayNext, ...navigationKeySetDayPrevious]);
Keyboard navigation automatically skips disabled dates and respects min/max boundaries.

Accessibility Features

  • Full keyboard navigation support
  • ARIA labels for all interactive elements
  • Screen reader announcements for date changes
  • Focus management for optimal navigation
  • High contrast mode support
When using disabled dates extensively, ensure there are selectable dates available. A calendar with all dates disabled provides a poor user experience.

Performance Considerations

For large numbers of disabled dates (50+), consider server-side date validation instead of passing hundreds of dates via the disabledDates property.
Use disabledDays instead of disabledDates when pattern-based disabling (e.g., all weekends) is sufficient - it’s more performant.

Next Steps

API Reference

Complete property and method documentation

Basic Usage

See more usage patterns and examples