Components/Date Picker

Date Picker

Twenty-one variants across three components: the field in fifteen, the bare trigger in three, and a time field in three. The calendar itself stays a separate component.

Date Picker · Components frameLive in the browser · drawn to match the file
Type
State
Pick a date
Type=Icon Right · State=Default212 × 32 in the file
With Input does not tint the field

Icon Left and Icon Right fill the whole 212px field with base.muted on Hover and Active, because the whole field is the button. With Input leaves the field white and lights only the 24px trailing button instead. Its Hover and Active look identical to Default at a glance, and that is right: a text field you can type into should not behave like a control you press.

the only 3px ring in the kit

Focus here is a 3px outer ring in base.ring, where every other component in the kit uses 2px. Time Picker matches it at 3px, so the pair is at least consistent with itself. Worth knowing if you are lining a date field up next to an Input, whose ring is a pixel thinner.

The other two

A bare trigger and a time field

Date Picker / Button is the calendar icon on its own, for a toolbar or the end of a row that already has its own field. Time Picker is the same 32px shell as the date field with a plain value in it, so a date and a time sit side by side at matching heights.

3 variants · 24 × 24 at radius 8
State

Its icon is base.foreground, not the base.muted-foreground the field uses. On its own it is a control; inside a field it is an affordance next to a placeholder, and the file weights them differently.

3 variants · 150 × 32 at radius 10
10:30:00
State

No Hover, because there is nothing to press: you type into it. Disabled drops the shell to half and takes the value down to base.muted-foreground as well, which is the one place the two pickers differ in how they grey out.

The usage frame

Five fields, one of them open

884 by 876. The last example drops a real Calendar / Basic instance under the trigger rather than drawing a picture of one, which is the whole argument for keeping Calendar separate. That one is live below: open it and pick a day.

A date field with its label
Start date
Pick a date
A range - two fields side by side
Check-in
12 Sep 2025
Check-out
Pick a date
A date and a time together
Delivery
24 Sep 2025
Time
10:30:00
Unavailable in a read-only form
Invoice date
Pick a date
Open - the calendar under the trigger
Meeting date
January 2025
Su
Mo
Tu
We
Th
Fr
Sa

The grid is a real January 2025: the 1st under Wednesday, three days of December before it and the 1st of February closing the last row. It comes from the Calendar component rather than being overridden here, which is what you want - a date grid whose weekdays do not line up is the first thing a reader checks, and an instance that overrides its calendar stops following the component it came from.

In the file

Three components, twenty-one variants

Read straight out of the Penpot file. The axes below are the property names you will see in the variant dropdown.

Date PickerState × TypeDefault · Hover · Focus · Active · Disabled × Icon Left · Icon Right · With Input15
Date Picker / ButtonStateDefault · Hover · Disabled - 24 × 243
Time PickerStateDefault · Focus · Disabled - 150 × 32, no Hover3

Using the Date Picker

Because the field does not tint, only its trailing 24px button does. Icon Left and Icon Right fill the whole 212px shell with base.muted on hover, since the whole shell is the button. With Input is a field you type into, so tinting it on hover would promise something it does not do.

It is the only place in the kit that uses 3px; everything else focuses at 2px. Time Picker matches it, so the two date controls are consistent with each other but a pixel heavier than an Input sitting beside them. Worth knowing when you line a form up.

Published separately, and the usage frame drops a real Calendar / Basic instance under the open trigger rather than drawing a picture of one. That is the point of keeping them apart: a date field, a range field and a booking widget can all open the same calendar without any of them owning a copy.

There is nothing to press. It is a value you type, so the file draws it at rest, focused, and disabled. Disabled also takes the value itself down to base.muted-foreground, which the date field does not do: the date field only drops the whole shell to half.

Yes. The 1st sits under Wednesday, which is where it fell in 2025, and the grid comes from the Calendar page rather than being overridden here. That matters more than it sounds: a date grid whose weekdays do not line up is the one thing every reader checks, and an instance that overrides its calendar stops following the component it came from.

Forms · 21 variants