TimeField
Since 0.1.0-alpha.20Static server-side rendering: no circuit, no WebAssembly.
A time of day.
Usage
<TimeField @bind-Value="Model.Opens" />
<TimeField @bind-Value="Model.Opens" Min="nine" Max="five" Step="TimeSpan.FromMinutes(15)" />
<TimeField @bind-Value="Model.Shift" Min="ten" Max="six" /> a window across midnight
<TimeField @bind-Value="Model.Opens" TimeDisabled="t => t.Hour == 12" />
<TimeField @bind-Value="Model.Opens" UseNative />Limits
Min and Max come from [Range], or set them on the field, as Closes's Min follows Opens. Set Min after Max for a window across midnight, as Night shift does.
Preview
Code
System.ComponentModel.DataAnnotations
<Form Model="Model" FormName="time-field-limits" OnValidSubmit="Save" MaxWidth="20.Rem" Grow>
<TimeField @bind-Value="Model!.Opens" Hint="Doors open in the morning." />
<TimeField @bind-Value="Model!.Closes" Min="Model!.Opens" />
<TimeField @bind-Value="Model!.Night" Label="Night shift starts" Min="new TimeOnly(22, 0)" Max="new TimeOnly(6, 0)" Hint="Between 10 PM and 6 AM." />
<Row><Button Submit>Save hours</Button></Row>
if (_saved is { } saved)
{
<Alert Status="Status.Success">Saved: open saved.Opens.ToString("HH:mm") to (saved.Closes?.ToString("HH:mm") ?? "late"), night shift from (saved.Night?.ToString("HH:mm") ?? "no one").</Alert>
}
</Form>
{
[SupplyParameterFromForm(FormName = "time-field-limits")]
private Hours? Model { get; set; }
// What was saved, not the fields: on an interactive page they follow typing.
private (TimeOnly Opens, TimeOnly? Closes, TimeOnly? Night)? _saved;
protected override void OnInitialized() => Model ??= new();
private void Save() => _saved = (Model!.Opens!.Value, Model.Closes, Model.Night);
public sealed class Hours
{
[Required, Range(typeof(TimeOnly), "06:00", "12:00", ErrorMessage = "Pick a time between 6 AM and noon.")]
public TimeOnly? Opens { get; set; } = new TimeOnly(9, 0);
public TimeOnly? Closes { get; set; }
public TimeOnly? Night { get; set; }
}
}Static: The server turns away a time outside the limits, whatever the browser let through.
The list of times
The list has a time every Step, or every 30 minutes with none, in which case the input still takes any minute. TimeDisabled turns times off, and holds on the server too. UseNative keeps the browser's picker.
Preview
Code
<Form Model="Model" FormName="time-field-slots" OnValidSubmit="Save" MaxWidth="20.Rem" Grow>
<TimeField @bind-Value="Model!.Visit" Min="new TimeOnly(9, 0)" Max="new TimeOnly(17, 0)" Step="TimeSpan.FromMinutes(15)" TimeDisabled="AtLunch" Clearable Hint="Every 15 minutes, 9 to 5, with no visits over lunch." />
<Row><Button Submit>Book the visit</Button></Row>
if (_saved is { } saved)
{
<Alert Status="Status.Success">Booked for saved.ToString("HH:mm").</Alert>
}
</Form>
{
[SupplyParameterFromForm(FormName = "time-field-slots")]
private Booking? Model { get; set; }
// What was saved, not the field: on an interactive page it follows typing.
private TimeOnly? _saved;
protected override void OnInitialized() => Model ??= new();
private static bool AtLunch(TimeOnly time) => time.Hour == 12;
private void Save() => _saved = Model!.Visit;
public sealed class Booking
{
public TimeOnly? Visit { get; set; } = new TimeOnly(10, 30);
}
}Steps, sizes, read-only and disabled
Use Step for the allowed increments; one under a minute shows seconds.
Preview
Code
<Form Model="Model" FormName="time-field-states" MaxWidth="20.Rem" Grow>
<TimeField @bind-Value="Model!.Quarter" Label="Quarter hours" Step="TimeSpan.FromMinutes(15)" />
<TimeField @bind-Value="Model!.Seconds" Label="With seconds" Step="TimeSpan.FromSeconds(1)" />
<TimeField @bind-Value="Model!.Small" Label="Small" Size="ControlSize.Sm" />
<TimeField @bind-Value="Model!.Large" Label="Large" Size="ControlSize.Lg" />
<TimeField @bind-Value="Model!.Signed" Label="Signed at" ReadOnly Hint="Read-only: posted, but can't be changed." />
<TimeField @bind-Value="Model!.Renews" Label="Renews at" Disabled Hint="Disabled: not posted." />
</Form>
{
[SupplyParameterFromForm(FormName = "time-field-states")]
private Contract? Model { get; set; }
protected override void OnInitialized() => Model ??= new();
public sealed class Contract
{
public TimeOnly Quarter { get; set; } = new(9, 15);
public TimeOnly Seconds { get; set; } = new(9, 15, 30);
public TimeOnly Small { get; set; } = new(9, 0);
public TimeOnly Large { get; set; } = new(9, 0);
public TimeOnly Signed { get; set; } = new(16, 30);
public TimeOnly Renews { get; set; } = new(0, 0);
}
}Details
A time has no date or zone, so nothing converts it. The input shows 12 or 24 hours as the browser does, which the page can't set; the list follows the page's culture.
The list has a time every Step, or every 30 minutes with no Step, in which case the input still takes any minute. With a Step of seconds, or one so short the list would pass 288 times, there's a box for each part of the time and OK instead, and nothing is written until OK. UseNative keeps the browser's picker. So do no script and a phone, unless the field has TimeDisabled, which a browser's picker can't show: there it's the library's, and on a phone the input can't be typed in. Min, Max and TimeDisabled are checked again on the server, and the boxes leave them to that and the browser.
Mode support
| Feature | Static | Interactive |
|---|---|---|
| The browser's input, with Min, Max and Step checked before posting, and Min, Max and disabled times checked again on the server | Yes | Yes |
| A list of times from Step, within Min and Max | Yes | Yes |
| Binds TimeOnly, and a window across midnight when Min is after Max | Yes | Yes |
Static: static server-side rendering, with no circuit and no WebAssembly. Interactive: Server, WebAssembly or Auto.
Without JavaScript
Every page starts as plain HTML: before IzzyBlazor's script loads on a static page, while an interactive page prerenders, and with JavaScript off. With JavaScript off, the browser's own picker opens in place of the library's list.
Accessibility
- It renders the browser's own time
inputwith alabellinked to it: screen readers read each part (hour, minute) and arrow keys change it. - Label, hint and errors work as in
TextField. - The list's button is named "Choose time" (
ChooseLabel), or "Change time" and the time once there is one. Its panel is a non-modaldialog, named by the button, holding alistbox, with the chosen time selected, or a labelled group of boxes. Focus goes to the chosen time, or the next from now, or the first box, and on closing back to where it opened from.
Keyboard navigation
In the time field
| Press this key | To do this |
|---|---|
| Up or Down | Change the focused part of the time |
| Left or Right | Move between the parts of the time |
| Alt+Down | Open the list |
In the list
| Press this key | To do this |
|---|---|
| Up or Down | Move a time |
| Home or End | Go to the first or last time |
| Enter or Space | Choose the time and close |
| Tab or Shift+Tab | Close, and go on from its button |
| Escape | Close without changing the value |
In the boxes
| Press this key | To do this |
|---|---|
| Up or Down | Change the hour, minute or second |
| Enter | Save the time, and close |
| Tab or Shift+Tab | Move through the boxes and OK, and close past either end |
| Escape | Close without changing the value |
Parameters
| Prop | Type | Default |
|---|---|---|
ReadOnlyMakes the field read-only: it can be focused, and it still posts. | bool | false |
MinThe earliest time. | TimeOnly? | computed |
MaxThe latest time. | TimeOnly? | computed |
StepThe step between allowed times, counted from Min, or from midnight with no Min. | TimeSpan? | |
TimeDisabledWhether a time can't be chosen. | Func<TimeOnly, bool>? | |
ClearableA button in the field that empties it, for a nullable value, there while it holds something. | bool | false |
UseNativeKeeps the browser's picker in place of the library's list. | bool | false |
ChooseLabelThe name of the list's button, in place of "Choose time" and "Change time" with the time. | string? | |
StartAddonContent attached before the control, outside its border. | RenderFragment? | |
EndAddonContent attached after the control, outside its border. | RenderFragment? | |
@bind-ValueThe value, bound with @bind-Value. | TValue | |
DisplayNameThe field's name in validation messages from the input itself, such as a value that can't be parsed. | string? |
Plus 26 field props.
Full API