Playbook's date picker is built using flatpickr, a vanilla js library. Common date picker use cases and features have been adapted into simple prop based configuration detailed in the docs below. You can implement additional features and functionality by accessing a flatpickr instance directly (demonstrated in the 'flatpickr methods' example below). This is done with the following code.
const fpInstance = document.querySelector('#pickerId')._flatpickr
pickerId
is a prop passed to the date picker kit. Flatpickr uses this id to target an input and attach a flatpickr instance to that input.
To learn more visit flatpickr's docs or see the hook doc section below for an applied example.
The Date Picker works best with Javascript Date Objects or ISO Date strings. If you're programming in js use Date Objects. If you're using rails convert your date object (with timezone) to UTC and then to an ISO Date string. For example, DateTime.now.utc.iso8601
. This ensures that the string passed to the Date Picker kit behaves as expected.
The Date Picker expects a date format of MM/DD/YYYY
by default. If a different date format (e.g. DD/MM/YYYY
, m/d/y
, etc.) is used, the component will not know how to handle it and use a default date instead. To change the date format used, read more here.
The defaultDate
/default_date
prop has a null or empty string value by default. You can pass an ISO date string (preferred rails method) or date object (preferred JS method) if you want a default value on page load. Use Ruby UTC DateTime objects and convert them to ISO date strings with DateTime.now.utc.iso8601
.
If you use a Date object without UTC time standardization the Date Picker kit may misinterpret that date as yesterdays date (consequence of timezone differentials and the Javascript Date Object constructor). See this GitHub issue for more information and the anti-pattern examples below.
<%= pb_rails("date_picker", props: { default_date: "07/25/2020", label: "Default Date String", picker_id: "date-picker-default-date1" }) %> <%= pb_rails("date_picker", props: { default_date: DateTime.current.utc.iso8601, label: "Default Date Dynamic", picker_id: "date-picker-default-date2" }) %> <%= pb_rails("date_picker", props: { label: "Default Behavior", picker_id: "date-picker-default-date4" }) %>
Setting the allowInput
prop to true permits users to key values directly into the input. This prop is set to false by default.
The date picker is built with the text input kit. Text input props you pass to the date picker kit will be forwarded to the input, with a few exceptions. The value
attribute is automatically handled and bound to whatever date string is contained by the input field. You cannot pass a custom value prop. id
props passed to the date picker kit will be assigned to it's parent/wrapper div. The pickerId
prop is passed directly to the input and is required to instatiate the date picker.
You must use inputAria
or input_aria
and inputData
or input_data
props if you wish to pass data or aria attributes to the text input kit. If you use data
or aria
props they will be passed to the date picker kit itself instead. Also be aware the default behavior of text input aria and data props is to pass those props to attributes on the wrapping div not on the input itself.
The placeholder prop has a default string value: "Select Date". You can replace this with your own string or an empty string if you'd prefer it blank.
<%= pb_rails("date_picker", props: { input_aria: { label: "input-field" }, input_data: { key: "value", key2: "value2" }, label: "Aria, Name, and Data Attributes", name: "date-field", picker_id: "date-picker-input1", }) %> <%= pb_rails("date_picker", props: { label: "Custom Placeholder", picker_id: "date-picker-input2", placeholder: "custom-placeholder", }) %> <%= pb_rails("date_picker", props: { label: "Blank Placeholder", picker_id: "date-picker-input3", placeholder: "" }) %> <%= pb_rails("date_picker", props: { disable_input: true, label: "Disable Input", picker_id: "date-picker-input4", placeholder: "Disabled Input" }) %>
Default label prop is "Date Picker"
. To remove the label set the hideLabel
prop in React or the hide_label
prop in Rails to true
.
This date range variant uses hidden inputs to handle start and end dates. While they are not required props, it is advisable to specify a unique start_date_id
, start_date_name
, end_date_id
, and end_date_name
for each quick pick instance you place in a form and/or on a page.
Like all other date pickers, the quick pick does require a picker_id
.
<%= pb_rails("date_picker", props: { allow_input: true, end_date_id: "quick-pick-end-date", end_date_name: "quick-pick-end-date", mode: "range", picker_id: "date-picker-quick-pick", placeholder: "mm/dd/yyyy to mm/dd/yyyy", selection_type: "quickpick", start_date_id: "quick-pick-start-date", start_date_name: "quick-pick-start-date" }) %>
Because the Quick Pick variant has allowInput
set to true
by default, use the onClose
handler function to access the startDate and endDate values. See the onClose
example for details.
<%= pb_rails("date_picker", props: { allow_input: true, end_date_id: "range-limit-end-date", end_date_name: "range-limit-end-date", mode: "range", picker_id: "thisRangesEndToday", placeholder: "mm/dd/yyyy to mm/dd/yyyy", selection_type: "quickpick", start_date_id: "range-limit-start-date", start_date_name: "range-limit-start-date", this_ranges_end_today: true }) %>
The customQuickPickDates/custom_quick_pick_dates prop allows for the user/dev to define their own quick pick dates.
The prop accepts an object with two key/value pairs: dates & override (separate doc example below).
The dates property accepts an array of objects. Each object in the array has label and value properties. The label is what will be displayed in the UI of the dropdown menu. The value property is just the date that is going to be passed to the datepicker. The value property can be an array of two strings that represent a range, allowing for the dev to be extremely specific. Additionally, the dates array allows for a clean, simple API under that automatically converts dates in a common vernacular.
The timePeriod property accepts "days", "weeks", "months", "quarters" or "years", representing past time periods.
The amount property accepts any number.
<%= pb_rails("date_picker", props: { allow_input: true, custom_quick_pick_dates: { dates: [ # Allow Playbook to handle the logic... { label: "Last 15 months", value: { timePeriod: "months", amount: 15, }, }, # Or, be explicit with an exact date range for more control... { label: "First Week of June 2022", value: ["06/01/2022", "06/07/2022"], }, ], }, end_date_id: "quick-pick-end-date", end_date_name: "quick-pick-end-date", mode: "range", picker_id: "date-picker-quick-pick-custom", placeholder: "mm/dd/yyyy to mm/dd/yyyy", selection_type: "quickpick", start_date_id: "quick-pick-start-date", start_date_name: "quick-pick-start-date" }) %>
The customQuickPickDates/custom_quick_pick_dates prop allows for an override boolean. The override allows for the user to completely override the quick pick dates that ship with the component. Default of override
is set to true. If you would like to simply append your dates to the default quick pick dates, set this prop to false explicitly.
<%= pb_rails("date_picker", props: { allow_input: true, custom_quick_pick_dates: { override: false, dates: [ { label: "Last 15 months", value: { timePeriod: "months", amount: 15, }, }, { label: "First Week of June 2022", value: ["06/01/2022", "06/07/2022"], }, ], }, end_date_id: "quick-pick-end-date", end_date_name: "quick-pick-end-date", mode: "range", picker_id: "date-picker-quick-pick-override", placeholder: "mm/dd/yyyy to mm/dd/yyyy", selection_type: "quickpick", start_date_id: "quick-pick-start-date", start_date_name: "quick-pick-start-date" }) %>
To set a default value using Quick Pick, use the defaultDate
or default_date
prop. This prop should match one of the labels displayed in the UI of the dropdown menu.
<%= pb_rails("date_picker", props: { allow_input: true, default_date: "This month", end_date_id: "quick-pick-end-date", end_date_name: "quick-pick-end-date", mode: "range", picker_id: "quick-pick-default-date", placeholder: "mm/dd/yyyy to mm/dd/yyyy", selection_type: "quickpick", start_date_id: "quick-pick-start-date", start_date_name: "quick-pick-start-date" }) %> <%= pb_rails("date_picker", props: { allow_input: true, custom_quick_pick_dates: { dates: [ { label: "Last 15 months", value: { timePeriod: "months", amount: 15, }, }, { label: "First Week of June 2022", value: ["06/01/2022", "06/07/2022"], }, ], }, default_date: "First Week of June 2022", end_date_id: "quick-pick-end-date", end_date_name: "quick-pick-end-date", label: "Custom Date Picker", mode: "range", picker_id: "custom-quick-pick-default-date", placeholder: "mm/dd/yyyy to mm/dd/yyyy", selection_type: "quickpick", start_date_id: "quick-pick-start-date", start_date_name: "quick-pick-start-date" }) %>
A full list of formatting tokens, i.e. "m/d/Y"
can be found here.
<%= pb_rails("date_picker", props: { default_date: DateTime.current.utc.iso8601, format: "m-d-Y", picker_id: "date-picker-format1" }) %> <%= pb_rails("date_picker", props: { default_date: DateTime.current.utc.iso8601, format: "m/d/y", picker_id: "date-picker-format2" }) %> <%= pb_rails("date_picker", props: { default_date: DateTime.current.utc.iso8601, format: "n-j-y", picker_id: "date-picker-format3" }) %> <%= pb_rails("date_picker", props: { default_date: DateTime.current.utc.iso8601, format: "Y-d-m", picker_id: "date-picker-format4" }) %>
<%= pb_rails("date_picker", props: { disable_date: [(DateTime.current + 1.day).utc.iso8601], label: "Disable Single Date", picker_id: "single-disabled-date" }) %> <%= pb_rails("date_picker", props: { disable_date: [(DateTime.current + 1.day).utc.iso8601, (DateTime.current + 2.day).utc.iso8601], label: "Disable Multiple Dates", picker_id: "multiple-disabled-dates" }) %> <%= pb_rails("date_picker", props: { disable_range: [ { from: DateTime.current.utc.iso8601, to: (DateTime.current + 7.day).utc.iso8601, }, ], label: "Disable Single Range", picker_id: "single-date-range" }) %> <%= pb_rails("date_picker", props: { disable_range: [ { from: (DateTime.current + 1.day).utc.iso8601, to: (DateTime.current + 2.day).utc.iso8601, }, { from: (DateTime.current + 7.day).utc.iso8601, to: (DateTime.current + 14.day).utc.iso8601, }, ], label: "Disable Multiple Ranges", picker_id: "multiple-date-ranges" }) %> <%= pb_rails("date_picker", props: { disable_weekdays: ['Sunday', 'Saturday'], label: "Disable Specific Weekdays", picker_id: "disabled-weekdays" }) %>
<%= pb_rails("date_picker", props: { label: "Dynamic dates", max_date: (DateTime.current + 1.day).utc.iso8601, min_date: (DateTime.current - 1.day).utc.iso8601, picker_id: "date-picker-min-max1" }) %> <%= pb_rails("date_picker", props: { format: "m/d/Y", label: "Absolute formatted dates", max_date: "10/20/2020", min_date: "10/10/2020", picker_id: "date-picker-min-max2" }) %>
<%= pb_rails("button", props: { id: "close-btn", margin_right: "sm", text: "Close" }) %> <%= pb_rails("button", props: { id: "clear-btn", margin_right: "sm", text: "Clear" }) %> <%= pb_rails("button", props: { id: "today-btn", text: "Today" }) %> <%= pb_rails("date_picker", props: { hide_label: true, margin_top: "sm", picker_id: "fp-methods" }) %> <%= javascript_tag do %> window.addEventListener("DOMContentLoaded", () => { const fp = document.querySelector("#fp-methods")._flatpickr const closeBtn = document.querySelector("#close-btn") const clearBtn = document.querySelector("#clear-btn") const todayBtn = document.querySelector("#today-btn") closeBtn.addEventListener("click", () => { fp.close() }) clearBtn.addEventListener("click", () => { fp.clear() }) todayBtn.addEventListener("click", () => { fp.setDate(new Date(), true) }) }) <% end %>
You can find a full list of flatpickr events and hooks in their documentation.
<%= pb_rails("date_picker", props: { label: "onChange", picker_id: "date-picker-hooks-onchange" }) %> <%= javascript_tag do %> window.addEventListener("DOMContentLoaded", () => { <%# Access flatpickr instance with picker id and assign it a variable %> const fp = document.querySelector("#date-picker-hooks-onchange")._flatpickr <%# Define Hook %> const changeHook = () => { alert('date changed') } <%# Push one or more hooks to onChange config array %> fp.config.onChange.push(changeHook) }) <% end %> <%= pb_rails("date_picker", props: { label: "onOpen", picker_id: "date-picker-hooks-onopen" }) %> <%= javascript_tag do %> window.addEventListener("DOMContentLoaded", () => { <%# Access flatpickr instance with picker id and assign it a variable %> const fp = document.querySelector("#date-picker-hooks-onopen")._flatpickr <%# Define Hook %> const openHook = () => { alert('calendar opened') } <%# Push one or more hooks to onOpen config array %> fp.config.onOpen.push(openHook) }) <% end %>
Defaults to [1900, 2100]
. Combine with min-max prop for best results.
<%= pb_rails("date_picker", props: { label: "Unformatted Date Object", default_date: Date.today, picker_id: "date-picker-anti-pattern1" }) %> <%= pb_rails("date_picker", props: { label: "Date Object Without Time - Displays Yesterday's Date", default_date: Date.today.to_datetime.utc.iso8601, picker_id: "date-picker-anti-pattern2" }) %> <%= pb_rails("date_picker", props: { label: "Unformatted DateTime Object", default_date: DateTime.current, picker_id: "date-picker-anti-pattern3" }) %> <%= pb_rails("date_picker", props: { label: "String Conversion Without ISO Formatting", default_date: DateTime.current.utc.to_s, picker_id: "date-picker-anti-pattern5" }) %>
<%= pb_rails("date_picker", props: { picker_id: "date-picker-none", margin_bottom: "none"}) %> <%= pb_rails("date_picker", props: { picker_id: "date-picker-xs", margin_bottom: "xs"}) %> <%= pb_rails("date_picker", props: { picker_id: "date-picker-sm", margin_bottom: "sm"}) %> <%= pb_rails("date_picker", props: { picker_id: "date-picker-md", margin_bottom: "md"}) %> <%= pb_rails("date_picker", props: { picker_id: "date-picker-lg", margin_bottom: "lg"}) %> <%= pb_rails("date_picker", props: { picker_id: "date-picker-xl", margin_bottom: "xl"}) %>
<%= pb_rails("date_picker", props: { classname: "inline-date-picker", hide_icon: true, inline: true, picker_id: "date-picker-inline" }) %> <%= javascript_tag do %> window.addEventListener("DOMContentLoaded", (event) => { const fpInline = document.querySelector("#date-picker-inline")._flatpickr <!-- Display the angle-down icon when a date has been selected --> const showAngleDownHandler = () => { document.querySelector('.inline-date-picker').classList.add('show-angle-down-icon') } fpInline.config.onChange.push(showAngleDownHandler) }) <% end %>
By default selectType prop is disabled. To activate it set selectionType
prop in JSX/TSX to month
. To activate it set selection_type
prop in a rails file to month
.
By default selectType prop is disabled. To activate it set selectionType
prop in JSX/TSX to week
. To activate it set selection_type
prop in a rails file to week
.
To select time as well, you should pass the enableTime
boolean prop. You can also enable timezone display by passing showTimezone
.
Datepicker supports position
options from Flatpickr Options Documentation. There are multiple positioning options to choose from.
Note: In order for the above prop to work properly, you must also send staticPosition={false}
to your Datepicker kit instance.
Upon adding static={false}
to the date picker, you will notice that the date picker detaches from the input field while scrolling. This is a known Flatpickr nuance. By adding the scrollContainer
prop, you can tell the date picker which DOM container it should watch for scroll events. In this example, you can see that scrollContainer=".pb--page--content--main"
is being passed in order to keep the date picker correctly positioned on page scroll.
Useage: scrollContainer: .validQuerySelectorHere
<%= pb_rails("flex") do %> <%= pb_rails("flex/flex_item", props: {fixed_size: "50%"}) do %> <%= pb_rails("date_picker", props: { label: "Datepicker (opens on the right)", picker_id: "date-picker-positions1", position: "auto right", scroll_container: ".pb--page--content--main", static_position: false }) %> <% end %> <% end %> <%= pb_rails("flex") do %> <%= pb_rails("flex/flex_item", props: {fixed_size: "50%"}) do %> <%= pb_rails("date_picker", props: { label: "Datepicker (opens on the left)", picker_id: "date-picker-positions2", position: "auto left", scroll_container: ".pb--page--content--main", static_position: false }) %> <% end %> <% end %> <%= pb_rails("flex") do %> <%= pb_rails("flex/flex_item", props: {fixed_size: "50%"}) do %> <%= pb_rails("date_picker", props: { label: "Datepicker (opens above on the left)", picker_id: "date-picker-positions3", position: "above left", scroll_container: ".pb--page--content--main", static_position: false }) %> <% end %> <% end %> <%= pb_rails("flex") do %> <%= pb_rails("flex/flex_item", props: {fixed_size: "50%"}) do %> <%= pb_rails("date_picker", props: { label: "Datepicker (opens below on the right)", picker_id: "date-picker-positions4", position: "below right", scroll_container: ".pb--page--content--main", static_position: false }) %> <% end %> <% end %>
<%= pb_rails("card", props: {id: "position-element", margin_bottom: "md"}) do %> <%= pb_rails("body") do %>👋 Datepicker will position from here based on ID.<% end %> <% end %> <%= pb_rails("flex") do %> <%= pb_rails("flex/flex_item", props: {fixed_size: "50%"}) do %> <%= pb_rails("date_picker", props: { label: "Datepicker (opens on the right)", picker_id: "date-picker-position-element", position: "auto right", position_element: "#position-element", scroll_container: ".pb--page--content--main", static_position: false }) %> <% end %> <% end %> <%= pb_rails("card", props: {classname: "position-element", margin_bottom: "md"}) do %> <%= pb_rails("body") do %>👋 Datepicker will position from here based on class name.<% end %> <% end %> <%= pb_rails("flex") do %> <%= pb_rails("flex/flex_item", props: {fixed_size: "50%"}) do %> <%= pb_rails("date_picker", props: { label: "Datepicker (opens on the right)", picker_id: "date-picker-position-element2", position: "auto right", position_element: ".position-element", scroll_container: ".pb--page--content--main", static_position: false }) %> <% end %> <% end %>
Props | Type | Values |
---|---|---|
max_width |
array
|
0%
xs
sm
md
lg
xl
xxl
0
none
100%
|
min_width |
array
|
0%
xs
sm
md
lg
xl
xxl
0
none
100%
|
width |
array
|
0%
xs
sm
md
lg
xl
xxl
0
none
100%
|
z_index |
array
|
1
2
3
4
5
6
7
8
9
10
|
number_spacing |
array
|
tabular
|
shadow |
array
|
none
deep
deeper
deepest
|
line_height |
array
|
tightest
tighter
tight
normal
loose
looser
loosest
|
display |
array
|
block
inline_block
inline
flex
inline_flex
none
|
cursor |
array
|
auto
default
none
contextMenu
help
pointer
progress
wait
cell
crosshair
text
verticalText
alias
copy
move
noDrop
notAllowed
grab
grabbing
eResize
nResize
neResize
nwResize
sResize
seResize
swResize
wResize
ewResize
nsResize
neswResize
nwseResize
colResize
rowResize
allScroll
zoomIn
zoomOut
|
flex_direction |
array
|
row
column
rowReverse
columnReverse
|
flex_wrap |
array
|
wrap
nowrap
wrapReverse
|
justify_content |
array
|
start
end
center
spaceBetween
spaceAround
spaceEvenly
|
justify_self |
array
|
auto
start
end
center
stretch
|
align_items |
array
|
flexStart
flexEnd
start
end
center
baseline
stretch
|
align_content |
array
|
start
end
center
spaceBetween
spaceAround
spaceEvenly
|
align_self |
array
|
auto
start
end
center
stretch
baseline
|
flex |
array
|
auto
initial
0
1
2
3
4
5
6
7
8
9
10
11
12
none
|
flex_grow |
array
|
1
0
|
flex_shrink |
array
|
1
0
|
order |
array
|
1
2
3
4
5
6
7
8
9
10
11
12
|
hover |
array
|
|
border_radius |
array
|
none
xs
sm
md
lg
xl
rounded
|
text_align |
array
|
start
end
left
right
center
justify
justify-all
match-parent
|
overflow |
array
|
visible
hidden
scroll
auto
|
truncate |
array
|
1
2
3
4
5
|
left |
array
|
0
xxs
xs
sm
md
lg
xl
auto
initial
inherit
|
top |
array
|
0
xxs
xs
sm
md
lg
xl
auto
initial
inherit
|
right |
array
|
0
xxs
xs
sm
md
lg
xl
auto
initial
inherit
|
bottom |
array
|
0
xxs
xs
sm
md
lg
xl
auto
initial
inherit
|
vertical_align |
array
|
baseline
super
top
middle
bottom
sub
text-top
text-bottom
|
height |
array
|
auto
xs
sm
md
lg
xl
xxl
xxxl
|
min_height |
array
|
auto
xs
sm
md
lg
xl
xxl
xxxl
|
max_height |
array
|
auto
xs
sm
md
lg
xl
xxl
xxxl
|
overflow_x |
array
|
visible
hidden
scroll
auto
|
overflow_y |
array
|
visible
hidden
scroll
auto
|
margin |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin_bottom |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin_left |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin_right |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin_top |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin_x |
array
|
none
xxs
xs
sm
md
lg
xl
|
margin_y |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding_bottom |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding_left |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding_right |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding_top |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding_x |
array
|
none
xxs
xs
sm
md
lg
xl
|
padding_y |
array
|
none
xxs
xs
sm
md
lg
xl
|
classname |
string
|
|
group_hover |
boolean
|
|
id |
string
|
|
data |
hashprop
|
|
aria |
hashprop
|
|
html_options |
hashprop
|
|
children |
proc
|
|
style |
hashprop
|
Props | Type | Values | Default |
---|---|---|---|
dark |
boolean
|
false
|
|
position |
string
|
auto
|
|
allow_input |
boolean
|
false
|
|
custom_quick_pick_dates |
hashprop
|
||
default_date |
string
|
||
disable_date |
array
|
||
disable_input |
boolean
|
false
|
|
disable_range |
array
|
||
disable_weekdays |
array
|
||
enable_time |
boolean
|
false
|
|
end_date_id |
string
|
end_date_id
|
|
end_date_name |
string
|
end_date_name
|
|
error |
string
|
||
format |
string
|
m/d/Y
|
|
hide_icon |
boolean
|
false
|
|
hide_label |
boolean
|
false
|
|
inline |
boolean
|
false
|
|
label |
string
|
Date Picker
|
|
input_aria |
hashprop
|
||
input_data |
hashprop
|
||
max_date |
string
|
||
min_date |
string
|
||
name |
string
|
||
mode |
string
|
single
|
|
picker_id |
string
|
||
placeholder |
string
|
Select Date
|
|
plugins |
boolean
|
false
|
|
position_element |
string
|
||
scroll_container |
string
|
||
selection_type |
enum
|
week
month
quickpick
none
|
none
|
show_timezone |
boolean
|
false
|
|
start_date_id |
string
|
start_date_id
|
|
start_date_name |
string
|
start_date_name
|
|
static_position |
boolean
|
true
|
|
this_ranges_end_today |
boolean
|
false
|
|
required |
boolean
|
false
|
|
year_range |
array
|
[1900, 2100]
|