For any iOS Developer, managing dates and times has historically been a source of headaches. From the hell of NSDateFormatter to the complexity of custom UIPickerView implementations in UIKit. However, the arrival of modern Swift programming and SwiftUI has drastically simplified this process.
Today we are going to dissect the DatePicker component in SwiftUI. We will not only learn how to display it, but how to master it, customize it, and adapt it to the particularities of iOS, macOS, and watchOS directly from Xcode.
What is DatePicker in SwiftUI?
The DatePicker is a native view structure designed to select an absolute date, a specific time, or both. The brilliance of using DatePicker in SwiftUI is its adaptability: it automatically handles localization, calendars (Gregorian, Japanese, etc.), and time format (12h/24h) based on the user’s device settings.
Basic Anatomy in Code
To implement a DatePicker, you fundamentally need a state variable (@State) of type Date that acts as the source of truth.
struct BasicDatePickerView: View {
@State private var selectedDate = Date()
var body: some View {
VStack {
Text("Selected date: \(selectedDate.formatted(date: .long, time: .shortened))")
.padding()
// The simplest constructor
DatePicker("Select date", selection: $selectedDate)
.padding()
}
}
}
Controlling Time: Ranges and Components
An iOS Developer rarely allows selecting *any* date. Generally, there are business rules. SwiftUI allows us to restrict this elegantly.
1. Limiting the Range (in: …)
Imagine a booking app where you can’t book in the past, or a birthday app where you can’t be born in the future.
<pre class="wp-block-syntaxhighlighter-code">struct BookingView: View {
@State private var bookingDate = Date()
// Range: From now to infinite future
let dateRange: PartialRangeFrom<Date> = Date()...
var body: some View {
DatePicker(
"Book your table",
selection: $bookingDate,
in: dateRange, // Here we apply the restriction
displayedComponents: [.date, .hourAndMinute]
)
}
}</pre>
2. Visual Components
Sometimes you only need the date (birthday) or only the time (alarm). The displayedComponents parameter is key.
.date: Shows only day, month, and year..hourAndMinute: Shows only hours and minutes.- Omit it to show both.
Styling the DatePicker: iOS vs macOS vs watchOS
Here is where DatePicker in SwiftUI shines for its versatility. The .datePickerStyle() modifier radically changes the UX depending on the platform.
Styles on iOS
On the iPhone, space is at a premium. We have three main options:
- .compact (Default): Shows the date/time in a button that, when tapped, displays a modal calendar or a wheel.
- .wheel: The classic “spinner” style from older iOS. Useful for precise time selectors (timers).
- .graphical: Displays the full calendar directly on the screen. Ideal for dashboards or selecting dates in large forms.
VStack {
// Visual Calendar Style
DatePicker("Calendar", selection: $date, displayedComponents: .date)
.datePickerStyle(.graphical)
.padding()
.background(Color.blue.opacity(0.1), in: RoundedRectangle(cornerRadius: 10))
}
Styles on macOS
On macOS, interaction is via mouse and keyboard. The .stepperField style (exclusive or default in certain Mac contexts) allows typing the date or using arrows.
Pro Tip: If you are making a Catalyst or native Mac app, .graphical also works excellently for sidebars.
#if os(macOS)
DatePicker("Date", selection: $date)
.datePickerStyle(.stepperField) // Desktop specific
#endif
Styles on watchOS
The Apple Watch is the final UX challenge. Here there is no space to waste. By default, watchOS stacks elements. Using .wheel on the watch is very common for timers.
Advanced Tutorial: The Multiplatform “Event Planner”
We are going to build a complete view that adapts to all three platforms using what we have learned about Swift programming.
import SwiftUI
struct EventPlannerView: View {
@State private var eventDate = Date()
@State private var isAllDay = false
// Validate that the event is in the future
var isValidDate: Bool {
eventDate >= Date()
}
var body: some View {
NavigationStack {
Form {
Section(header: Text("Event Details")) {
Toggle("All day", isOn: $isAllDay)
// Conditional logic for components
DatePicker(
"Starts",
selection: $eventDate,
in: Date()..., // Do not allow past
displayedComponents: isAllDay ? .date : [.date, .hourAndMinute]
)
// Smart style adaptation
#if os(iOS)
.datePickerStyle(.compact)
#elseif os(macOS)
.datePickerStyle(.stepperField)
#endif
}
Section {
if isValidDate {
Text("\(Int(eventDate.timeIntervalSinceNow / 3600)) hours until the event")
.foregroundStyle(.blue)
} else {
Text("Date cannot be in the past")
.foregroundStyle(.red)
}
}
// Example of graphical style for iOS/macOS
#if !os(watchOS)
Section(header: Text("Calendar View")) {
DatePicker("Calendar", selection: $eventDate, displayedComponents: .date)
.datePickerStyle(.graphical)
}
#endif
}
.navigationTitle("New Event")
}
}
}
#Preview {
EventPlannerView()
}
Expert Tricks in Xcode
1. Hiding the Label
Often, UI design requires the DatePicker to be centered or without text on the left. You can use labelsHidden().
DatePicker("Hidden Title", selection: $date)
.labelsHidden() // Only shows the date control
2. Automatic Internationalization
Don’t try to force dd/mm/yyyy formats manually inside the picker. SwiftUI detects the user’s region. If the user is in the US, they will see mm/dd/yyyy. If they are in Spain, they will see dd/mm/yyyy. Trust the system.
3. UIDatePicker vs SwiftUI DatePicker
Although DatePicker in SwiftUI is powerful, if you need to change the text color of the “wheel” on iOS, it is still difficult to do natively without hacks. In those extreme cases, an iOS Developer might choose to wrap a UIDatePicker with UIViewRepresentable, but for 99% of cases, the SwiftUI version is superior in performance and ease of code.
Conclusion
The DatePicker in SwiftUI is a testament to how Swift programming has evolved to prioritize declarative functionality over tedious imperative implementation. You no longer need to calculate row heights or manage complex delegates.
Mastering this component in Xcode allows you to create robust, accessible, and aesthetically pleasing data entry interfaces across the entire Apple ecosystem.
If you have any questions about this article, please contact me and I will be happy to help you 🙂. You can contact me on my X profile or on my Instagram profile.