custom-headless-date-field
v1.0.0
Published
Accessible, animated date picker with keyboard navigation and dark mode
Readme
DateField Component
Description
The DateField component is a fully accessible, animated date picker with built-in dark mode support and flexible styling options. It features portal-based calendar rendering, keyboard navigation, manual date input with auto-formatting (mm/dd/yyyy), and comprehensive date validation.
Installation
npm install custom-headless-date-field@latestFeatures
- ✅ Portal-based calendar - Calendar opens above other elements with viewport-aware positioning
- ✅ Manual date input - Type dates directly with auto-formatting (mm/dd/yyyy)
- ✅ Built-in dark mode support with custom theme variables
- ✅ Date validation - Automatic validation and formatting
- ✅ Min/Max date constraints - Restrict selectable date ranges
- ✅ Full keyboard navigation - Arrow keys, Enter/Space, Escape, Tab
- ✅ WCAG 2.1 AA accessible - ARIA roles, labels, screen reader support
- ✅ Error state - Validation error display with
erroranderrorMessageprops - ✅ Smooth animations - Fade and scale transitions on open/close
- ✅ Today indicator - Subtle ring highlights the current date
- ✅ Flexible customization - Extensive styling props
- ✅ Custom theme variables - Predefined color palette
Usage
import React, { useState } from "react";
import { DateField } from "custom-headless-date-field";
const App = () => {
const [birthDate, setBirthDate] = useState("");
const [eventDate, setEventDate] = useState("");
return (
<div>
{/* Basic Date Field */}
<DateField
label="Date of Birth"
value={birthDate}
onChange={setBirthDate}
max="12/31/2010" // Only allow dates before 2011
/>
{/* Date Field with Custom Styling */}
<DateField
label="Event Date"
value={eventDate}
onChange={setEventDate}
min="01/01/2024" // Only allow future dates
className="border-blue-300 focus:ring-blue-500"
calendarClassName="bg-blue-50 dark:bg-blue-900 border border-blue-200"
calendarSelectedDayClassName="bg-blue-600 text-white"
/>
</div>
);
};Props
Core Props
| Prop | Type | Required | Description |
| ---------- | ------------------------ | -------- | ---------------------------------- |
| value | string | ✅ | Selected date in mm/dd/yyyy format |
| onChange | (date: string) => void | ✅ | Callback when date changes |
Optional Props
| Prop | Type | Default | Description |
| ------- | -------- | ------- | ------------------------------------ |
| label | string | - | Label displayed above the date field |
| min | string | - | Minimum selectable date (mm/dd/yyyy) |
| max | string | - | Maximum selectable date (mm/dd/yyyy) |
| disabled | boolean | false | Disables the input and calendar |
| error | boolean | false | Shows error styling on the input |
| errorMessage | string | - | Error message displayed below the input |
| placeholder | string | mm/dd/yyyy | Placeholder text for the input |
| required | boolean | false | Marks the field as required |
Styling Props
| Prop | Type | Description |
| ------------------------------ | -------- | --------------------------------------- |
| className | string | Custom styling for the input field |
| calendarClassName | string | Custom styling for the calendar popup |
| calendarDayClassName | string | Custom styling for individual day cells |
| calendarSelectedDayClassName | string | Custom styling for the selected day |
| iconClass | string | Custom styling for the calendar icon |
Keyboard Navigation
| Key | Action |
| ------------ | ------------------------------------------- |
| Arrow Left | Move to previous day |
| Arrow Right| Move to next day |
| Arrow Up | Move to same day in previous week |
| Arrow Down | Move to same day in next week |
| Enter | Select the focused day and close calendar |
| Space | Select the focused day and close calendar |
| Escape | Close calendar without selecting |
| Tab | Close calendar and move to next form field |
Arrow keys automatically cross month boundaries and skip disabled dates (outside min/max range).
Accessibility
- Calendar popup uses
role="dialog"witharia-modal="true" - Each day button has a descriptive
aria-label(e.g., "Tuesday, April 15, 2026") - Month/year heading uses
aria-live="polite"for screen reader announcements - Label is properly associated with the input via
htmlFor/id - Error messages use
role="alert"andaria-live="polite" - Input includes
aria-invalid,aria-required, andaria-describedbyas appropriate
Styles
The DateField component uses Tailwind CSS classes and supports Tailwind CSS v4.1.11 with built-in dark mode support.
Built-in Theme Variables
The component includes custom theme variables for consistent styling:
background-dark- Custom dark background color (#212529)button-approve- Primary approval button color (#2c3034)button-approve-dark- Dark mode approval button color (#93a6e2)purple- Accent purple color (#7286d3)- Additional color variables for various UI states
CSS Setup
Ensure Tailwind CSS is properly set up in your project. In your main CSS file:
@import "tailwindcss";
/* Your other styles */Important: The DateField component requires Tailwind CSS to be available in your project for styling to work properly.
Dark Mode Support
The component automatically adapts to dark mode when the dark class is present on a parent element:
// Enable dark mode for the entire app
<body className="dark">
<App />
</body>
// Or scope it to a specific section
<div className="dark">
<DateField ... />
</div>Advanced Usage
Date Input Formatting
The component automatically formats dates as you type:
- Input:
12252023→ Formatted:12/25/2023 - Input:
1252023→ Formatted:01/25/2023 - Supports both typing and calendar selection
Custom Styling Example
<DateField
label="Custom Styled Date Picker"
value={date}
onChange={setDate}
className="border-purple focus:ring-purple bg-background dark:bg-background-dark"
calendarClassName="bg-background dark:bg-background-dark border border-purple"
calendarSelectedDayClassName="bg-button-approve text-white dark:bg-button-approve-dark"
iconClass="text-purple"
/>Error State
<DateField
label="Date of Birth"
value={date}
onChange={setDate}
error={!isValid}
errorMessage="Please enter a valid date"
required
/>Date Range Constraints
<DateField
label="Event Date"
value={eventDate}
onChange={setEventDate}
min="01/01/2024" // No dates before 2024
max="12/31/2024" // No dates after 2024
/>Date Format
The DateField component uses mm/dd/yyyy format:
- Input format:
mm/dd/yyyy(e.g.,12/25/2023) - Auto-formatting: Automatically adds slashes as you type
- Validation: Only accepts valid dates in the correct format
Customization
The DateField component offers extensive customization options:
- Complete styling control through styling props
- Manual date input with automatic formatting
- Calendar popup for visual date selection
- Date range constraints via min/max props
- Built-in dark mode support with custom theme variables
- Portal-based rendering for proper layering
- Custom theme integration using predefined color variables
- Error state support with customizable error messages
- Smooth open/close animations with scale and opacity transitions
