use-date-input
v2.0.0
Published
React hooks for building date input and datepicker components.
Downloads
3
Maintainers
Readme
use-date-input
React hooks for building date input and datepicker components.
Installation
To use this hook you need to install date-fns.
yarn add date-fns
yarn add use-date-input
or with npm:
npm install date-fns
npm install use-date-input
useDateInput
▸ useDateInput(props
: UseDateInputProps
): UseDateInput
Hook that manages state of masked date input.
Uses IMask for input masking and date-fns for date formatting and parsing.
Props
UseDateInputProps
| Name | Type | Description |
| :------ | :------ | :------ |
| dateFormat
| string
| date-fns date format, see https://date-fns.org/v2.22.1/docs/format |
| maskBlocks?
| MaskedDateOptions
["blocks"
] | Blocks defining each date part, see https://imask.js.org/guide.html#masked-date for more info |
| onComplete?
| (value?
: Date
) => void
| This will execute when input satisfies given format (mask), usually this function should be used to update date value|
| value?
| Date
| Date value of input |
Return value
UseDateInput
| Name | Type | Description |
| :------ | :------ | :------ |
| inputValue
| string
| Value of input element |
| onKeyPress
| KeyboardEventHandler
| Apply to input element if you wish to autocomplete date when user presses enter key. Parsing is done using dateFns parse with dateFormat truncated to the length of current inputValue and using current date as reference. For example if today is 07/08/2021 and input value is 2, on enter press, input value will become 02/08/2021 |
| ref
| RefObject
<HTMLInputElement
> | Input element ref |
| resetValueOnDelete
| ChangeEventHandler
<HTMLInputElement
> | Will call onComplete with undefined value if e.target.value is falsy. Use it to reset value when user deletes the input. |
| setInputValue
| Dispatch
<SetStateAction
<string
>> | Sets inputValue, note that you don't need to set input value on input element change, this is done internally by using IMask's accept event |
Usage
// define maskBlocks as constant or memoize in component
const maskBlocks = {
dd: {
mask: IMask.MaskedRange,
from: 1,
to: 31,
maxLength: 2,
},
MM: {
mask: IMask.MaskedRange,
from: 1,
to: 12,
maxLength: 2,
},
yyyy: {
mask: IMask.MaskedRange,
from: 1900,
to: 9999,
},
};
const DateInput = () => {
const [value, setValue] = useState<Date>();
const { ref, inputValue, resetValueOnDelete } = useDateInput({
value,
dateFormat: "dd-MM-yyyy",
maskBlocks,
onComplete: setValue,
});
return <input ref={ref} value={inputValue} onChange={resetValueOnDelete} />;
};
useCalendar
▸ useCalendar(props
: UseCalendarProps
): UseCalendar
Manages calendar state.
You can use this hook to render calendar view. Focused date state is used as reference to return calendar days.
Uses date-fns for date manipulation.
Props
UseCalendarProps
| Name | Type | Description |
| :------ | :------ | :------ |
| maxDate?
| Date
| Only dates before this date will be marked valid For best performance memoize this date, this will prevent recalculation of calendar days on each render. |
| minDate?
| Date
| Only dates after this date will be marked valid. For best performance memoize this date, this will prevent recalculation of calendar days on each render. |
| startDate?
| Date
| If provided calendar will start at the month of provided date |
| validate?
| (date
: Date
) => boolean
| Validation function, dates that fail this test will be marked invalid. For best performance memoize this function, this will prevent recalculation of calendar days on each render. |
| value?
| Date
| Datepicker value |
| weekStartsOn?
| 0
1
2
3
4
5
6
| Day that a week starts on. 0 - sunday, 1 - monday ..., default is 0 |
Return value
UseCalendar
| Name | Type | Description |
| :------ | :------ | :------ |
| days
| UseDatepickerDay
[] | Returns all dates that can be seen in calendar view along with flags for each date that indicate if it is in the same month as focused date and if it is valid (available for selection). Use this function to render month view of calendar. |
| focusedDate
| Date
| First day of month that represents current calendar view |
| isSelected
| (date
: Date
) => boolean
| Compares given date with value. |
| months
| Date
[] | Dates representing each month in the same year as focusedDate. You can use this function render month selection for calendar view. |
| nextMonth
| () => void
| Adds one month to focusedDate. Use it to move calendar view to next month. |
| nextYear
| () => void
| Adds one year to focusedDate. Use it to move calendar view to next year. |
| previousMonth
| () => void
| Subtracts one month from focusedDate. Use it to move calendar view to previous month. |
| previousYear
| () => void
| Adds one month to focusedDate. Use it to move calendar view to next month. |
| setFocusedDate
| Dispatch
<SetStateAction
<Date
>> | Changes focusedDate, make sure to only pass first day of the month dates. By changing focusedDate you are actually changing the reference point of calendar which means, once focused date is changed, days and months functions will use new focusedDate value as reference point. |
| years?
| Date
[] | Dates representing eachYear from minDate to maxDate. Returns undefined if minDate or maxDate is not defined |
UseDatePickerDay
| Name | Type | Description |
| :------ | :------ | :------ |
| date
| Date
| Represents calendar day |
| inMonth
| boolean
| Indicates if this date is in currently viewed calendar month |
| isValid
| boolean
| If true this date can be selected according to provided min and max date and validate function |
Usage
const Calendar = () => {
const [value, setValue] = useState<Date>();
const { previousYear, nextYear, focusedDate, previousMonth, nextMonth, days, isSelected } = useCalendar({ value });
return (
<div style={{ width: "420px" }}>
<div style={{ width: "100%" }}>
<button onClick={previousYear}>{"<"}</button>
{format(focusedDate, "yyyy")}
<button onClick={nextYear}>{">"}</button>
</div>
<div style={{ width: "100%" }}>
<button onClick={previousMonth}>{"<"}</button>
{format(focusedDate, "MMMM")}
<button onClick={nextMonth}>{">"}</button>
</div>
<div style={{ display: "flex", flexWrap: "wrap" }}>
{days.map(({ date, inMonth }) => (
<button
disabled={!inMonth}
style={{ width: "60px", backgroundColor: isSelected(date) ? "aliceblue" : "initial" }}
key={date.toDateString()}
onClick={() => setValue(date)}>
{format(date, "d")}
</button>
))}
</div>
</div>
);
};
useDatepicker
▸ useDatepicker<T
>(props
: UseCalendarProps
& UseDropdownProps
): UseCalendar
& UseDropdown
<T
>
Combines useCalendar and useDropdown hooks into one.
Props
| Name | Type | Description |
| :------ | :------ | :------ |
| additionalRefs?
| RefObject
<HTMLElement
>[] | These refs will be used when determining what constitutes a click outside of dropdown. |
| disabled?
| boolean
| If true, open and close will do nothing |
| onClose?
| () => void
| Executed when close is called |
| onOpen?
| () => void
| Executed when open is called |
| maxDate?
| Date
| Only dates before this date will be marked valid For best performance memoize this date, this will prevent recalculation of calendar days on each render. |
| minDate?
| Date
| Only dates after this date will be marked valid. For best performance memoize this date, this will prevent recalculation of calendar days on each render. |
| startDate?
| Date
| If provided calendar will start at the month of provided date |
| validate?
| (date
: Date
) => boolean
| Validation function, dates that fail this test will be marked invalid. For best performance memoize this function, this will prevent recalculation of calendar days on each render. |
| value?
| Date
| Datepicker value |
| weekStartsOn?
| 0
1
2
3
4
5
6
| Day that a week starts on. 0 - sunday, 1 - monday ..., default is 0 |
Return value
| Name | Type | Description |
| :------ | :------ | :------ |
| dropdownRef
| RefObject
<T
> | Ref for dropdown element |
| isOpen
| boolean
| Dropdown state |
| open
| () => void
| Sets isOpen to true |
| close
| () => void
| Sets isOpen to false |
| days
| UseDatepickerDay
[] | Returns all dates that can be seen in calendar view along with flags for each date that indicate if it is in the same month as focused date and if it is valid (available for selection). Use this function to render month view of calendar. |
| focusedDate
| Date
| First day of month that represents current calendar view |
| isSelected
| (date
: Date
) => boolean
| Compares given date with value. |
| months
| Date
[] | Dates representing each month in the same year as focusedDate. You can use this function render month selection for calendar view. |
| nextMonth
| () => void
| Adds one month to focusedDate. Use it to move calendar view to next month. |
| nextYear
| () => void
| Adds one year to focusedDate. Use it to move calendar view to next year. |
| previousMonth
| () => void
| Subtracts one month from focusedDate. Use it to move calendar view to previous month. |
| previousYear
| () => void
| Adds one month to focusedDate. Use it to move calendar view to next month. |
| setFocusedDate
| Dispatch
<SetStateAction
<Date
>> | Changes focusedDate, make sure to only pass first day of the month dates. By changing focusedDate you are actually changing the reference point of calendar which means, once focused date is changed, days and months functions will use new focusedDate value as reference point. |
| years?
| Date
[] | Dates representing eachYear from minDate to maxDate. Returns undefined if minDate or maxDate is not defined |
Usage
const DateInputWithDatepicker = () => {
const [value, setValue] = useState<Date>();
const { ref, inputValue, resetValueOnDelete } = useDateInput({
value,
dateFormat: "dd-MM-yyyy",
maskBlocks,
onComplete: setValue,
});
const {
isOpen,
open,
days,
previousYear,
nextYear,
previousMonth,
nextMonth,
focusedDate,
dropdownRef,
isSelected,
} = useDatepicker<HTMLDivElement>({
value,
});
return (
<div ref={dropdownRef}>
<input ref={ref} value={inputValue} onChange={resetValueOnDelete} onFocus={open} />
{isOpen && (
<div style={{ width: "420px" }}>
<div style={{ width: "100%" }}>
<button onClick={previousYear}>{"<"}</button>
{format(focusedDate, "yyyy")}
<button onClick={nextYear}>{">"}</button>
</div>
<div style={{ width: "100%" }}>
<button onClick={previousMonth}>{"<"}</button>
{format(focusedDate, "MMMM")}
<button onClick={nextMonth}>{">"}</button>
</div>
<div style={{ display: "flex", flexWrap: "wrap" }}>
{days.map(({ date, inMonth }) => (
<button
disabled={!inMonth}
style={{ width: "60px", backgroundColor: isSelected(date) ? "aliceblue" : "initial" }}
key={date.toDateString()}
onClick={() => setValue(date)}>
{format(date, "d")}
</button>
))}
</div>
</div>
)}
</div>
);
};