figma guide

Designing date pickers and calendar UI in Figma: patterns, states, and handoff

Design date pickers, range selectors, and calendar grids in Figma with input states, presets, timezone notes, and Dev Mode specs for forms and filters.

Published
Updated
Jun 13, 2026
Read time
9 min
Level
Beginner

Quick answer

Date pickers in Figma combine a text input, calendar popover, and optional presets—single date, date range, or month/year-only modes. Build a DatePicker component with variants for mode=single | range | month, state=default | open | disabled | error, and size=sm | md. Pair the calendar grid with forms, dropdowns, and tables filters. Document date format, min/max bounds, disabled dates, timezone handling, and keyboard behavior in Dev Mode—engineering cannot infer these from a static calendar frame. Start from the Figma guides hub for component basics.


Who this is for

  • Product designers shipping booking flows, reports, filters, and scheduling screens.
  • Design system teams replacing inconsistent date fields copied from random Dribbble shots.
  • Engineers implementing locale-aware parsing, range selection, and accessible calendar grids.

Picker types compared

TypeUser selectsBest forAvoid when
Single dateOne dayBirthdays, due dates, appointmentsSelecting a week-long vacation with two taps
Date rangeStart + endReports, bookings, analytics filtersSingle-day events
Month pickerMonth + yearBilling cycles, statementsDay-level precision needed
Date + timeDay + hour/minuteMeetings, deadlinesDate-only reporting
Inline calendarAlways visible gridAvailability, scheduling dashboardsCompact filter bars
Preset chips”Last 7 days”, “This month”Analytics, admin filtersLegal contracts needing exact dates

Verdict: default to popover + input for forms; use inline calendar only when the grid is the primary interaction (booking, availability). Combine presets with a range picker for search and filter bars.


Component anatomy

PartPurposeSpec tip
Input fieldShows formatted date(s)Placeholder: locale format (MM/DD/YYYY vs DD/MM/YYYY)
Calendar iconOpens popoverOptional on mobile if tap opens native picker
Popover panelMonth grid + navMin width ~280px; shadow/elevation token
Month headerPrev/next + month labelChevron buttons 32–40px hit area
Weekday rowMon–Sun labelsUse locale start-of-week
Day cellSelectable date36–40px square; today ring
Range highlightIn-between dayssurface/selected-subtle between endpoints
Footer actionsClear, Today, ApplyRequired for range + filter contexts
Preset listQuick ranges (optional)Left column in wide popover
DatePicker
├── Variant: mode=single | range | month
├── Variant: state=default | open | disabled | error
├── Variant: size=sm | md
├── Layer: Input (reuse TextField from forms)
│   ├── Value text
│   └── Calendar icon button
├── Layer: Popover (absolute below input)
│   ├── Presets (optional, vertical list)
│   ├── CalendarHeader (prev | "June 2026" | next)
│   ├── WeekdayRow (7 labels)
│   ├── DayGrid (6 rows × 7 cols)
│   └── Footer (Clear | Today | Apply)
└── Layer: Helper / error text

Bind day text styles to your typography scale. Use semantic color tokens for selected, hover, disabled, and today states.


Day cell states

StateVisualNotes
DefaultNeutral text on surfacePointer on hover
HoverSubtle backgroundNot on disabled days
SelectedSolid brand fill; inverse textSingle or range endpoint
In rangeLight fill between endpointsRange mode only
TodayRing or dot; not same as selectedCan be both today + selected
Outside monthMuted textStill clickable or not—document
DisabledMuted; no pointerPast dates, blackout days
FocusVisible focus ringKeyboard grid navigation

Reuse interactive components for day cells. Selected and today must differ when they overlap—e.g., filled selected + outer ring for today.


Date range selection flow

StepUISpec
1User opens pickerPopover below input
2First clickSets start; hover previews range
3Second clickSets end; closes or waits for Apply
4Invalid orderAuto-swap start/end or block—pick one
5Same-day rangeAllow or treat as single day—document
6Apply (filters)Commits to table query

Show partial range in the input after first click (Jun 3 – …). For analytics, pair with chips showing active range on the filter bar.


Input field and formatting

ConcernDesign decisionHandoff note
Display formatJun 13, 2026 vs 13/06/2026locale prop; do not hardcode in mocks only
PlaceholderMatches formatSelect date vs MM/DD/YYYY
Manual typingAllowed or picker-onlyValidation on blur
Clear buttonIcon inside inputResets value + closes popover
Error stateRed border + message”Date unavailable” vs “Invalid format”
Min / maxDisable out-of-range daysminDate, maxDate in spec

Align field heights with your form input sizes—sm for dense tables, md for standard forms.


Presets for filters and reports

PresetRange logicTypical use
TodayStart = end = todayOps dashboards
Last 7 daysRolling 7 daysSupport queues
Last 30 daysRolling 30Analytics default
This month1st → last day of current monthBilling
Last monthPrevious calendar monthFinance reports
CustomOpens full pickerPower users

Layout: presets as a left column (140–160px) when popover is wide; on mobile, use a bottom sheet with preset list above the grid.


Month and year navigation

ControlPatternAccessibility
Prev / next monthChevron in headeraria-label="Previous month"
Month label clickOpens month/year dropdownFaster jump than 12 next clicks
Year stepperIn month picker modeFor birth year far in past
Decade viewOptional for DOBGrid of years

Prototype at least: default month, month dropdown open, and year picker frames. Note whether future months are disabled (e.g., scheduling only).


Timezone and locale (do not skip)

TopicWhat to documentWhy
TimezoneUTC storage vs local display”Jun 13” shifts for global users
Start of weekSunday vs MondayGrid column order
Fiscal calendarNon-standard quartersEnterprise reporting
HolidaysDisabled dates arrayBooking products
12h vs 24hIf time is includedPair with time sub-input

Add a sticky note on booking flows: “All times shown in America/Vancouver” or use the user’s local zone—pick one product-wide rule.


Pairing with other patterns

NeedPatternLink
Filter barDate range + searchReports, admin lists
Booking confirmationModal summaryShow selected range
Empty resultsEmpty state”No data for this period”
Loading dataSkeleton on tableAfter Apply
Validation errorsInline alertConflicting dates

Accessibility checklist

RequirementImplementation
LabelVisible label or aria-label on input
Grid rolerole="grid" with role="gridcell" per day
Selectedaria-selected="true"
Disabled daysaria-disabled="true"
Live regionAnnounce month change on nav
KeyboardArrow keys move; Enter selects; Esc closes
Focus trapOptional inside popover until Apply
ColorSelected state not color-only

Run accessibility plugins on selected vs today contrast.


Prototyping limits

Figma cannot compute real dates or locale. For demos:

  1. Build frames: closed, open single, open range (partial), month dropdown.
  2. Wire calendar icon → open; Apply → closed with filled input.
  3. Use sticky comments for dynamic behavior (disabled weekends, min date = today).

Organize flows with sections per screen.


Handoff to engineering

DeliverableWhere it lives
mode valuessingle, range, month
Date format stringsPer locale table
minDate / maxDateComponent description
Disabled date rulesFunction or list spec
First day of week0 (Sun) or 1 (Mon)
Range apply behaviorAuto-close vs explicit Apply
Timezone policyUTC vs local
Mobile behaviorNative picker vs custom popover
Popover placementFlip above if no room below

Include date pickers in your Dev Mode handoff checklist. Publish under Patterns / Forms in your team library.


Real-world examples

Analytics filter bar

Compact range input with presets (7d, 30d, Custom). Apply refreshes table below. Active range shown as a chip next to search.

Hotel booking

Inline two-month calendar; range highlight; disabled past dates; checkout min-stay rules in component description. Price per night on day cells (optional tier).

Employee DOB (HR form)

Single date; month/year dropdown for fast year jump; max date = today; manual typing allowed with validation message.


Common mistakes

MistakeConsequenceFix
One date format in mocksWrong locale in productionDocument locale + examples
Today = selected same styleUsers lose orientationRing + fill combo
No Apply on range filtersTable updates on every clickExplicit Apply for data queries
Tiny day cells (<32px)Miss taps on mobile36–40px minimum
Ignoring timezoneOff-by-one day bugsPolicy note on every booking flow
6×7 grid with wrong start dayMisaligned weekdaysMatch locale week start
Range without hover previewConfusing second clickShow in-between highlight on hover
Popover clipped in modalsUnusable pickerFlip placement or use modal layer spec

FAQ

Popover vs inline calendar?

Popover saves space in forms and filters. Inline works when picking dates is the main task (booking, scheduling).

Native mobile date picker vs custom?

Native is faster to ship and familiar on iOS/Android. Custom when you need range, presets, or brand calendar styling—document which screens use which.

Show two months side by side?

Common for travel range selection. Ensure popover min-width (~560px) or full-width on mobile sheet.

Date picker in a table cell?

Use sm size; popover opens upward if near viewport bottom. Consider filter row above table instead of per-cell pickers.


Bottom line

Design date pickers as a system: input, popover, calendar grid, presets, and clear locale/timezone rules—not a pretty month screenshot. Document modes, bounds, disabled logic, and Apply behavior in Dev Mode. Continue with forms, search filters, tables, and the tutorials hub.

Share on X

§ Keep reading

Related guides.