Component
DateField
A segmented date/time input component with explicit format strings and full keyboard navigation.
Demo
Selected: 2026-01-08
Selected: 2026-01-08 09:21
Selected: 01/08/2026 09:21 AM
Features
- Segmented editing (each part is independently editable)
- Explicit format strings - no CultureInfo dependency, no extra WASM downloads
- Support for both DateOnly and DateTime types
- 12-hour and 24-hour time formats via TimeFormat parameter
- Localized segment labels and AM/PM from browser's Intl API
- Min/max validation and EditForm integration
- WCAG compliant with proper ARIA attributes
Installation
bash
dotnet add package SummitUIAnatomy
Import the components and structure them as follows:
razor
<DateFieldRoot @bind-Value="date" Format="yyyy-MM-dd" class="group">
<DateFieldLabel>Select a date</DateFieldLabel>
<DateFieldInput class="..." />
</DateFieldRoot>Sub-components
DateFieldRoot
Root container managing date field state.
DateFieldLabel
Accessible label for the date field.
DateFieldInput
Container that renders date/time segments.
DateFieldSegment
Individual editable segment (auto-generated).
API Reference
DateFieldRoot
| Property | Type | Default | Description |
|---|---|---|---|
| Formatrequired | string | - | Date format pattern (e.g., "yyyy-MM-dd", "MM/dd/yyyy") |
| TimeFormat | string | "HH:mm" | Time format pattern. Use "hh:mm" for 12-hour, "HH:mm" for 24-hour |
| Value | DateOnly? | null | Bound DateOnly value (date only, no time) |
| ValueChanged | EventCallback<DateOnly?> | - | DateOnly value change callback |
| DateTimeValue | DateTime? | null | Bound DateTime value (shows time segments) |
| DateTimeValueChanged | EventCallback<DateTime?> | - | DateTime value change callback |
| Placeholder | DateOnly | Today | Placeholder date shown when Value is null |
| DateTimePlaceholder | DateTime | Now | Placeholder datetime shown when DateTimeValue is null |
| MinValue | DateOnly? | null | Minimum allowed DateOnly value |
| MaxValue | DateOnly? | null | Maximum allowed DateOnly value |
| MinDateTime | DateTime? | null | Minimum allowed DateTime value |
| MaxDateTime | DateTime? | null | Maximum allowed DateTime value |
| Disabled | bool | false | Disables the entire date field |
| ReadOnly | bool | false | Makes the field read-only |
| Invalid | bool | false | Indicates validation error state |
| Name | string? | null | Form field name for submission |
| Required | bool | false | Marks the field as required |
Format Strings
No CultureInfo Required
DateField uses explicit format strings instead of CultureInfo. This means no need to enable
BlazorWebAssemblyLoadAllGlobalizationData (which adds ~2-3MB to your WASM bundle).
Screen reader labels and AM/PM text are still localized using the browser's Intl API.
Date Format Examples
| Format | Region | Example Output |
|---|---|---|
| yyyy-MM-dd | ISO / Sweden | 2025-01-15 |
| MM/dd/yyyy | United States | 01/15/2025 |
| dd/MM/yyyy | United Kingdom | 15/01/2025 |
| dd.MM.yyyy | Germany | 15.01.2025 |
Time Format Examples
| TimeFormat | Clock Type | Example Output |
|---|---|---|
| HH:mm | 24-hour (default) | 14:30 |
| hh:mm | 12-hour with AM/PM | 02:30 PM |
| HH.mm | 24-hour with dot separator | 14.30 |
Use lowercase h for 12-hour format (shows AM/PM), uppercase H for 24-hour format.
Examples
Basic DateOnly Field
razor
@code {
private DateOnly? selectedDate = DateOnly.FromDateTime(DateTime.Today);
}
<DateFieldRoot @bind-Value="selectedDate" Format="yyyy-MM-dd" class="group">
<DateFieldLabel>Select a date</DateFieldLabel>
<DateFieldInput class="..." />
</DateFieldRoot>
<p>Selected: @(selectedDate?.ToString("yyyy-MM-dd") ?? "None")</p>DateTime with Time
Bind to DateTimeValue to show time segments.
razor
@code {
private DateTime? selectedDateTime = DateTime.Now;
}
<DateFieldRoot @bind-DateTimeValue="selectedDateTime"
Format="yyyy-MM-dd"
class="group">
<DateFieldLabel>Select date and time</DateFieldLabel>
<DateFieldInput class="..." />
</DateFieldRoot>
<p>Selected: @(selectedDateTime?.ToString("yyyy-MM-dd HH:mm") ?? "None")</p>12-Hour Time Format
Use lowercase 'h' in TimeFormat for 12-hour clock with AM/PM.
razor
@code {
private DateTime? dateTime = DateTime.Now;
}
<DateFieldRoot @bind-DateTimeValue="dateTime"
Format="MM/dd/yyyy"
TimeFormat="hh:mm"
class="group">
<DateFieldLabel>Select date and time</DateFieldLabel>
<DateFieldInput class="..." />
</DateFieldRoot>
<p>Selected: @(dateTime?.ToString("MM/dd/yyyy hh:mm tt") ?? "None")</p>Min/Max Validation
Constrain the date range.
razor
@code {
private DateOnly? date = DateOnly.FromDateTime(DateTime.Today);
private DateOnly minDate = new DateOnly(2025, 1, 1);
private DateOnly maxDate = new DateOnly(2025, 12, 31);
}
<DateFieldRoot @bind-Value="date"
Format="yyyy-MM-dd"
MinValue="@minDate"
MaxValue="@maxDate"
class="group">
<DateFieldLabel>Select a date (Jan - Dec 2025)</DateFieldLabel>
<DateFieldInput class="..." />
</DateFieldRoot>EditForm Integration
Use with Blazor forms and validation.
razor
<EditForm EditContext="editContext" OnSubmit="HandleSubmit">
<DataAnnotationsValidator />
<DateFieldRoot @bind-Value="model.BirthDate"
Format="yyyy-MM-dd"
Name="birthDate"
Required="true"
Invalid="@(submitted && model.BirthDate == null)"
class="group">
<DateFieldLabel>Birth Date (Required)</DateFieldLabel>
<DateFieldInput class="..." />
</DateFieldRoot>
<ValidationMessage For="@(() => model.BirthDate)" />
<button type="submit">Submit</button>
</EditForm>Styling
Data Attributes
| Attribute | Values | Description |
|---|---|---|
| data-disabled | Present when disabled | Date field is disabled |
| data-readonly | Present when read-only | Date field is read-only |
| data-invalid | Present when invalid | Validation error state |
| data-placeholder | Present when no value | Showing placeholder |
| data-segment | Segment type | Identifies segment type for styling |
Tailwind Example
html
<!-- DateFieldInput with Tailwind classes -->
<DateFieldInput class="inline-flex items-center px-3 py-2 bg-su-background
border border-su-border rounded-lg text-sm mt-2 transition-all min-w-[200px]
focus-within:border-su-primary focus-within:ring-2 focus-within:ring-su-primary/20
group-data-[disabled]:opacity-50 group-data-[disabled]:cursor-not-allowed
group-data-[invalid]:border-su-destructive
[&_[data-segment]:not([data-segment='literal'])]:px-1.5
[&_[data-segment]:not([data-segment='literal'])]:py-0.5
[&_[data-segment]:not([data-segment='literal'])]:rounded-md
[&_[data-segment]:not([data-segment='literal'])]:min-w-[1.5em]
[&_[data-segment]:not([data-segment='literal'])]:text-center
[&_[data-segment]:not([data-segment='literal'])]:focus:bg-su-primary/10
[&_[data-segment]:not([data-segment='literal'])]:focus:text-su-primary
[&_[data-segment='literal']]:text-su-muted-foreground
[&_[data-segment][data-placeholder]]:text-su-muted-foreground/60" />Accessibility
Keyboard Navigation
| Key | Action |
|---|---|
| ArrowUp | Increment the focused segment value |
| ArrowDown | Decrement the focused segment value |
| ArrowLeft | Move focus to previous segment |
| ArrowRight | Move focus to next segment |
| Tab | Move focus to next segment (or next element) |
| 0-9 | Type numeric value directly into segment |
| Backspace / Delete | Clear the value (sets to null) |
| A / P | Toggle AM/PM on DayPeriod segment |
ARIA Attributes
- Root:
Has
role="group"witharia-labelledbypointing to label - Segments:
Each has
role="spinbutton"witharia-valuemin,aria-valuemax,aria-valuenow - Labels: Segment labels (Year, Month, etc.) are localized from the browser's Intl.DisplayNames API
- Literals:
Separator segments have
aria-hidden="true"