@archpublicwebsite/rangepicker
v1.0.14
Published
Custom date range picker component for PBA Hotel Apps
Maintainers
Readme
@archpublicwebsite/rangepicker
Custom, lightweight date range picker component for Vue 3 with Tailwind CSS prefix support.
Features
- 🎨 Vue 3 Composition API - Built with modern Vue 3 and TypeScript
- 📦 CSS Prefix Support - All Tailwind classes prefixed with
arch-to prevent conflicts with Vuetify/Bootstrap - 📅 Dayjs Integration - Powerful date manipulation without moment.js bloat
- 🎨 Themeable - Easy color customization via props (HEX colors)
- 📱 Mobile Responsive - Touch-friendly with bottom sheet on mobile
- 🎯 Smart Positioning - Auto-adjusts based on available viewport space
- ♿ Accessible - Keyboard navigation and screen reader support
- 🚀 SSR Compatible - Works perfectly with Nuxt 3
- 🪶 Lightweight - ~49KB CSS (gzipped: 5.3KB), ~40KB JS (gzipped: 9.4KB)
Installation
npm install @archpublicwebsite/rangepicker
# or
pnpm add @archpublicwebsite/rangepicker
# or
yarn add @archpublicwebsite/rangepickerQuick Start
Important: You must import both the component AND the CSS file.
<script setup>
import { ref } from 'vue'
import { RangepickerInput } from '@archpublicwebsite/rangepicker'
import '@archpublicwebsite/rangepicker/style.css' // Required!
const dates = ref('')
</script>
<template>
<RangepickerInput
v-model="dates"
primary-color="#3b82f6"
placeholder="Check in / Check out"
/>
</template>TypeScript Support
Full TypeScript support with exported types for type-safe development:
<script setup lang="ts">
import { ref } from 'vue'
import {
RangepickerInput,
type RangepickerProps,
type DateRange
} from '@archpublicwebsite/rangepicker'
import '@archpublicwebsite/rangepicker/style.css'
// Type-safe date range
const dates = ref<DateRange>({ startDate: '', endDate: '' })
// Type-safe props configuration
const pickerOptions: Partial<RangepickerProps> = {
format: 'DD/MM/YYYY',
autoApply: true,
minDays: 2,
maxDays: 30,
showTooltip: true
}
</script>
<template>
<RangepickerInput
v-model="dates"
v-bind="pickerOptions"
primary-color="#3b82f6"
placeholder="Check in / Check out"
/>
</template>Why separate CSS import?
- Better performance (CSS cached independently)
- Smaller JS bundle
- No Flash of Unstyled Content (FOUC)
- Industry standard (like Vuetify, Element Plus, etc.)
Tailwind CSS Prefix:
All Tailwind utility classes are prefixed with arch- to prevent conflicts with other CSS frameworks like Vuetify or Bootstrap. Your existing styles won't be affected!
Color Customization
Customize colors easily by passing HEX color values as props. Each rangepicker instance can have its own color scheme:
<script setup>
import { ref } from 'vue'
import { RangepickerInput } from '@archpublicwebsite/rangepicker'
import '@archpublicwebsite/rangepicker/style.css'
const dates1 = ref('')
const dates2 = ref('')
const dates3 = ref('')
</script>
<template>
<!-- Blue theme -->
<RangepickerInput
v-model="dates1"
primary-color="#3b82f6"
secondary-color="#60a5fa"
placeholder="Blue theme"
/>
<!-- Purple theme -->
<RangepickerInput
v-model="dates2"
primary-color="#8b5cf6"
secondary-color="#a78bfa"
placeholder="Purple theme"
/>
<!-- Red theme -->
<RangepickerInput
v-model="dates3"
primary-color="#ef4444"
secondary-color="#f87171"
placeholder="Red theme"
/>
</template>Color Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| primary-color | string | - | Main color for selected dates and buttons (HEX format, e.g., #3b82f6) |
| secondary-color | string | - | Color for hover states and secondary elements (HEX format, optional) |
Features:
- ✅ Scoped per instance - Multiple pickers can have different colors simultaneously
- ✅ No global state - Colors don't conflict between instances
- ✅ HEX format - Standard 3 or 6 digit HEX colors (e.g.,
#3b82f6,#fff) - ✅ Auto-conversion - Automatically converts HEX to RGB for CSS variables
- ✅ Optional - Falls back to default theme if not provided
Framework Compatibility
This package is designed to work seamlessly with any Vue 3 framework:
- ✅ Vuetify - No CSS conflicts thanks to
arch-prefix - ✅ Bootstrap - Works alongside Bootstrap utilities
- ✅ Element Plus - Fully compatible
- ✅ Quasar - No issues
- ✅ Plain Vue 3 - Works great standalone
- ✅ Nuxt 3 - SSR compatible
The arch- prefix on all Tailwind classes ensures zero conflicts with other CSS frameworks.
Usage
With Vuetify (Recommended)
<script setup>
import { ref } from 'vue'
import { RangepickerInput } from '@archpublicwebsite/rangepicker'
import '@archpublicwebsite/rangepicker/style.css'
import '@archpublicwebsite/rangepicker/style.css'
const dates = ref('')
const options = {
autoApply: true,
minDate: new Date(),
format: 'DD MMM YYYY',
numberOfColumns: 2,
numberOfMonths: 2,
}
</script>
<template>
<v-container>
<RangepickerInput
v-model="dates"
:options="options"
primary-color="#1976d2"
placeholder="Check in / Check out"
class="my-custom-input"
/>
</v-container>
</template>Basic Usage
<script setup lang="ts">
import { ref, computed } from 'vue'
import { Rangepicker, type DateRange } from '@archpublicwebsite/rangepicker'
import '@archpublicwebsite/rangepicker/style.css'
const triggerRef = ref<HTMLElement | null>(null)
const isOpen = ref(false)
const dateRange = ref<DateRange>({ startDate: '', endDate: '' })
const dateRangeText = computed(() => {
if (!dateRange.value.startDate || !dateRange.value.endDate) return ''
return `${dateRange.value.startDate} - ${dateRange.value.endDate}`
})
</script>
<template>
<div>
<input
ref="triggerRef"
type="text"
:value="dateRangeText"
placeholder="Select dates"
readonly
@click="isOpen = true"
/>
<Rangepicker
v-model="dateRange"
v-model:is-open="isOpen"
:trigger-element="triggerRef"
:value-of-months="2"
format="DD MMM YYYY"
/>
</div>
</template>Using the Composable
<script setup lang="ts">
import { ref } from 'vue'
import {
Rangepicker,
useRangepicker,
type RangepickerProps
} from '@archpublicwebsite/rangepicker'
import '@archpublicwebsite/rangepicker/style.css'
const triggerRef = ref<HTMLElement | null>(null)
// Type-safe composable options
const options: Partial<RangepickerProps> = {
valueOfMonths: 2,
format: 'DD MMM YYYY',
minDays: 1,
autoApply: true
}
const { isOpen, dateRange, open, close, toggle } = useRangepicker(triggerRef, options)
</script>
<template>
<div>
<button ref="triggerRef" @click="toggle">
{{ dateRange.startDate && dateRange.endDate
? `${dateRange.startDate} - ${dateRange.endDate}`
: 'Select dates' }}
</button>
<Rangepicker
v-model="dateRange"
v-model:is-open="isOpen"
:trigger-element="triggerRef"
v-bind="options"
/>
</div>
</template>Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| modelValue | { startDate?: string \| Date \| Dayjs, endDate?: string \| Date \| Dayjs } | {} | Selected date range |
| isOpen | boolean | false | Controls picker visibility |
| variant | 'desktop' \| 'mobile' | 'desktop' | Display variant |
| primaryColor | string | - | Primary color in HEX format (e.g., #3b82f6) |
| secondaryColor | string | - | Secondary color in HEX format (e.g., #60a5fa) |
| minDate | string \| Date \| Dayjs | - | Minimum selectable date |
| maxDate | string \| Date \| Dayjs | - | Maximum selectable date |
| minDays | number | - | Minimum number of days in range |
| maxDays | number | - | Maximum number of days in range |
| valueOfMonths | number | 2 | Number of months to display |
| valueOfColumns | number | 2 | Grid columns for months |
| disabledDates | (string \| Date)[] | [] | Array of disabled dates |
| holidays | (string \| Date)[] | [] | Array of holiday dates |
| format | string | 'YYYY-MM-DD' | Date format |
| delimiter | string | ' - ' | Delimiter between dates |
| placeholder | string | 'Select dates' | Placeholder text |
| label | string | - | Label for the picker |
| showTooltip | boolean | true | Show night count tooltip |
| autoApply | boolean | false | Auto-apply selection |
| position | 'auto' \| 'top' \| 'bottom' | 'auto' | Positioning strategy |
| triggerElement | HTMLElement \| null | - | Trigger element for positioning |
Events
| Event | Payload | Description |
|-------|---------|-------------|
| update:modelValue | { startDate: string, endDate: string } | Emitted when date range changes |
| update:isOpen | boolean | Emitted when picker opens/closes |
| dateSelected | Dayjs | Emitted when a date is clicked |
| rangeSelected | { start: Dayjs, end: Dayjs } | Emitted when range is complete |
TypeScript Support
This package is built with TypeScript and provides full type definitions. All types are automatically exported for your convenience.
Available Types
import type {
RangepickerProps, // Component props interface
RangepickerEmits, // Event emitter interface
DateRange, // Date range object type
CalendarDay, // Internal calendar day type
CalendarMonth // Internal calendar month type
} from '@archpublicwebsite/rangepicker'Type Definitions
RangepickerProps
Complete props interface with JSDoc documentation. All props are optional with sensible defaults:
interface RangepickerProps {
modelValue?: { startDate?: string | Date | Dayjs; endDate?: string | Date | Dayjs }
isOpen?: boolean
variant?: 'desktop' | 'mobile'
minDate?: string | Date | Dayjs
maxDate?: string | Date | Dayjs
minDays?: number
maxDays?: number
close?: boolean
valueOfMonths?: number // default: 2
valueOfColumns?: number // default: 2
disabledDates?: (string | Date)[]
holidays?: (string | Date)[]
format?: string // default: 'YYYY-MM-DD'
delimiter?: string // default: ' - '
placeholder?: string
label?: string
showTooltip?: boolean // default: true
autoApply?: boolean // default: false
position?: 'auto' | 'top' | 'bottom'
triggerElement?: HTMLElement | null
colorStyles?: Record<string, string>
}DateRange
Type for the v-model binding:
interface DateRange {
startDate: string
endDate: string
}RangepickerEmits
Event emitter types for type-safe event handling:
interface RangepickerEmits {
'update:modelValue': [value: { startDate: string; endDate: string }]
'update:isOpen': [value: boolean]
'dateSelected': [date: Dayjs]
'rangeSelected': [start: Dayjs, end: Dayjs]
}Usage Examples
Type-Safe Component Props
import type { RangepickerProps } from '@archpublicwebsite/rangepicker'
// Define props with autocomplete support
const config: Partial<RangepickerProps> = {
format: 'DD/MM/YYYY',
minDays: 2,
maxDays: 30,
autoApply: true,
showTooltip: true
}Type-Safe Event Handlers
import type { Dayjs } from 'dayjs'
function handleDateSelected(date: Dayjs) {
console.log('Selected:', date.format('YYYY-MM-DD'))
}
function handleRangeSelected(start: Dayjs, end: Dayjs) {
const nights = end.diff(start, 'day')
console.log(`Booking: ${nights} nights`)
}Type-Safe Refs
import { ref } from 'vue'
import type { DateRange } from '@archpublicwebsite/rangepicker'
const dateRange = ref<DateRange>({ startDate: '', endDate: '' })
const holidays = ref<string[]>(['2025-12-25', '2025-01-01'])
const disabledDates = ref<Date[]>([new Date('2025-12-24')])IDE Support
With the exported types, you'll get:
- ✅ Autocomplete - IntelliSense for all props and events
- ✅ Type Checking - Compile-time error detection
- ✅ Documentation - Hover tooltips with prop descriptions and default values
- ✅ Refactoring - Safe rename and refactor operations
- ✅ Error Prevention - Catch typos and incorrect prop usage before runtime
Development
# Install dependencies
pnpm install
# Start dev server with demo
pnpm dev
# Build package
pnpm build
# Type check
pnpm type-check
# Preview build
pnpm previewCSS Architecture
The component uses Tailwind CSS with arch- prefix to prevent conflicts with other frameworks:
Why the prefix?
- ✅ Zero conflicts with Vuetify, Bootstrap, Element Plus, etc.
- ✅ Safe to use alongside any CSS framework
- ✅ All utilities prefixed:
.arch-flex,.arch-text-sm,.arch-bg-white, etc. - ✅ Custom classes untouched:
.rangepicker-*classes remain unprefixed
Styling Options
- Color Props (Easiest):
<RangepickerInput
primary-color="#3b82f6"
secondary-color="#60a5fa"
/>- CSS Variables (Global):
:root {
--color-primary: 59 130 246; /* RGB format */
--color-secondary: 148 163 184;
}- Custom CSS Overrides:
/* Override component styles */
.rangepicker-day-selected {
background-color: purple !important;
}Troubleshooting
Styles not showing
Make sure you imported the CSS:
import '@archpublicwebsite/rangepicker/style.css'CSS conflicts with Vuetify
This should NOT happen thanks to the arch- prefix. If you see conflicts, please open an issue.
TypeScript errors
Ensure vue is installed as a dependency in your project.
Browser Support
- Chrome/Edge (latest 2 versions)
- Firefox (latest 2 versions)
- Safari (latest 2 versions)
- Mobile Safari (iOS 14+)
- Chrome for Android (latest)
Contributing
See the main repository README for contribution guidelines.
License
MIT © Archipelago International
