# DateRangeInput
*Select date ranges with an intuitive calendar [interface](../../01_Onboarding/02_Concepts/02_Views.md) for start and end dates, perfect for filtering and event scheduling.*
The `DateRangeInput` [widget](../../01_Onboarding/02_Concepts/03_Widgets.md) allows users to select a range of dates. It provides a calendar interface for both start and end date selection, making it ideal for filtering data by date ranges or scheduling events.
## Basic Usage
Here's a simple example of a `DateRangeInput` that allows users to select a date range:
```csharp
public class BasicDateRangeDemo : ViewBase
{
public override object? Build()
{
var dateRangeState = this.UseState(() => (from: DateTime.Today.AddDays(-7), to: DateTime.Today));
var start = dateRangeState.Value.Item1;
var end = dateRangeState.Value.Item2;
var span = $"That's {(end-start).Days} days";
return Layout.Vertical()
| dateRangeState.ToDateRangeInput()
| Text.P(span).Large();
}
}
```
As can be seen, the starting and ending date of the date range can be extracted using the
`DateTimeRange.Value.Item1` and `DateTimeRange.Value.Item2`
## Supported Types
DateRangeInput supports DateOnly tuple types:
- `(DateOnly, DateOnly)` - Date-only range
- `(DateOnly?, DateOnly?)` - Nullable date-only range
## Variants
The `DateRangeInput` can be customized with various states. The following example demonstrates **Disabled**, **Invalid**, and **Nullable** states:
```csharp
public class DateRangeVariantsDemo : ViewBase
{
public override object? Build()
{
var dateRange = this.UseState(() =>
(from: DateTime.Today.AddDays(-7), to: DateTime.Today));
var nullableRange = this.UseState<(DateOnly?, DateOnly?)>(() =>
(DateOnly.FromDateTime(DateTime.Today.AddDays(-7)),
DateOnly.FromDateTime(DateTime.Today)));
return Layout.Vertical().Gap(4)
| Text.P("Disabled State").Small()
| dateRange.ToDateRangeInput().Disabled()
| Text.P("Invalid State").Small()
| dateRange.ToDateRangeInput().Invalid("Invalid date range")
| Text.P("Nullable State").Small()
| nullableRange.ToDateRangeInput();
}
}
```
## Format
To change the format of selected dates the `Format` function needs to be used.
```csharp
public class FormatDateRangeDemo : ViewBase
{
public override object? Build()
{
var dateRangeState = this.UseState(() =>
(from: DateTime.Today.AddDays(-7), to: DateTime.Today));
return Layout.Vertical()
| dateRangeState.ToDateRangeInput()
.Format("yyyy-MM-dd");
}
}
```
## API
[View Source: DateRangeInput.cs](https://github.com/Ivy-Interactive/Ivy-Framework/blob/main/src/Ivy/Widgets/Inputs/DateRangeInput.cs)
### Constructors
| Signature |
|-----------|
| `new DateRangeInput<TDateRange>(IAnyState state, string placeholder = null, bool disabled = false)` |
| `new DateRangeInput<TDateRange>(TDateRange value, Func<Event<IInput<TDateRange>, TDateRange>, ValueTask> onChange, string placeholder = null, bool disabled = false)` |
| `new DateRangeInput<TDateRange>(TDateRange value, Action<Event<IInput<TDateRange>, TDateRange>> onChange, string placeholder = null, bool disabled = false)` |
| `new DateRangeInput<TDateRange>(string placeholder = null, bool disabled = false)` |
| `ToDateRangeInput(IAnyState state, string placeholder = null, bool disabled = false)` |
### Supported Types
| Group | Type | Nullable |
|-------|------|----------|
| Other | `ValueTuple<DateOnly, DateOnly>` | - |
| Other | `ValueTuple<DateOnly?, DateOnly?>` | - |
### Properties
| Name | Type | Setters |
|------|------|---------|
| `Disabled` | `bool` | `Disabled` |
| `Format` | `string` | `Format` |
| `Height` | `Size` | - |
| `Invalid` | `string` | `Invalid` |
| `Nullable` | `bool` | `Nullable` |
| `Placeholder` | `string` | `Placeholder` |
| `Scale` | `Scale?` | - |
| `Value` | `TDateRange` | - |
| `Visible` | `bool` | - |
| `Width` | `Size` | - |
### Events
| Name | Type | Handlers |
|------|------|----------|
| `OnBlur` | `Func<Event<IAnyInput>, ValueTask>` | `HandleBlur` |
| `OnChange` | `Func<Event<IInput<TDateRange>, TDateRange>, ValueTask>` | - |
## Examples
### Hotel Booking Example
A realistic example demonstrating a hotel booking form with date range selection, validation, and price calculation:
```csharp
public class HotelBookingDemo : ViewBase
{
private const decimal PricePerNight = 120m;
public override object? Build()
{
var bookingRange = this.UseState<(DateOnly?, DateOnly?)>(() => (null, null));
var from = bookingRange.Value.Item1;
var to = bookingRange.Value.Item2;
var nights = from.HasValue && to.HasValue
? (to.Value.ToDateTime(TimeOnly.MinValue) - from.Value.ToDateTime(TimeOnly.MinValue)).Days
: 0;
var isValid = nights >= 1;
var errorMessage = !isValid && from.HasValue ? "Minimum stay is 1 night" : "";
var totalPrice = nights * PricePerNight;
return Layout.Vertical().Gap(4)
| Text.P("Book Your Stay").Large().Bold()
| bookingRange.ToDateRangeInput()
.Placeholder("Select check-in and check-out dates")
.Format("MMM dd, yyyy")
.Invalid(errorMessage)
| (nights > 0
? Layout.Horizontal().Gap(2)
| Text.P($"{nights} night(s)").Small().Muted()
| Text.P($"Total: ${totalPrice}").Small().Bold()
: null);
}
}
```