# CircularTimePicker
## Description
A BitCircularTimePicker picks a single time from an analog clock dial: an hour ring the pointer snaps to, then a minute ring and an optional second ring, with an AM/PM pair in 12-hour mode. It can be driven with a pointer or entirely from the keyboard, restricted to a range or a step, edited as text, laid out portrait or landscape, and rendered either inline or in a callout that becomes a sheet on small screens.
## Parameters
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| AllowedHours | `Func<int, bool>?` | null | The hours that can be selected, on top of what MinTime, MaxTime and HourStep already allow. The predicate receives an hour of the day (0-23) whichever TimeFormat the clock is in. |
| AllowedMinutes | `Func<int, bool>?` | null | The minutes that can be selected, on top of what MinTime, MaxTime and MinuteStep already allow. The predicate receives a minute of the hour (0-59). |
| AllowedSeconds | `Func<int, bool>?` | null | The seconds that can be selected, on top of what MinTime, MaxTime and SecondStep already allow. The predicate receives a second of the minute (0-59). |
| AllowTextInput | `bool` | false | Whether the TimePicker allows input a time string directly or not. The text is parsed with the exact ValueFormat of the picker. |
| AmPmInClock | `bool` | false | Renders the AM/PM pair under the clock instead of beside the time in the toolbar. Only the 12-hour format has a meridiem to place. |
| AutoClose | `bool` | false | Closes the callout as soon as the selection is complete - the last part the dial offers is picked, or the "now" button is used - without waiting for the close button or a click outside of it. |
| AutoFocus | `bool` | false | If true, the input of the TimePicker automatically receives focus when the page renders. |
| CalloutAriaLabel | `string` | Clock | Aria label for time picker popup for screen reader users. |
| CalloutFooterTemplate | `RenderFragment?` | null | Custom template to render at the bottom of the callout, below everything it holds. |
| CalloutHeaderTemplate | `RenderFragment?` | null | Custom template to render at the top of the callout, above everything it holds. |
| CalloutHtmlAttributes | `Dictionary<string, object>` | new Dictionary<string, object>() | Capture and render additional attributes in addition to the main callout's parameters. |
| Classes | `BitCircularTimePickerClassStyles` | null | Custom CSS classes for different parts of the TimePicker. |
| ClearButtonText | `string` | Clear | The text of the button that clears the value of the TimePicker. |
| CloseButtonIcon | `BitIconInfo?` | null | The icon for the close button using external icon libraries. Takes precedence over CloseButtonIconName when both are set. |
| CloseButtonIconName | `string?` | Cancel | The name of the icon for the close button from the built-in Fluent UI icons. For external icon libraries, use CloseButtonIcon instead. |
| CloseButtonTitle | `string` | Close time picker | The title of the close button (tooltip). |
| Color | `BitColor?` | null | The general color of the TimePicker, applied to the toolbar, the dial pointer and the selected numbers. |
| Culture | `CultureInfo?` | CultureInfo.CurrentUICulture | CultureInfo for the TimePicker. |
| DropDirection | `BitDropDirection` | BitDropDirection.TopAndBottom | Determines the allowed drop directions of the callout. |
| EditMode | `BitCircularTimePickerEditMode` | BitCircularTimePickerEditMode.Normal | Choose the edition mode. By default, you can edit every part the picker shows. |
| HasBorder | `bool` | true | Determines if the TimePicker has a border. |
| HourButtonTitle | `string` | Select hour | The title (and accessible name) of the button that switches the dial to the hours. |
| HourStep | `int` | 1 | The step, in hours, the dial and the keyboard move the hour by. A step greater than 1 lays a grid over the day that the pick snaps to, dimming the hours in between, starting at the hour of MinTime and at midnight where there is none. |
| Icon | `BitIconInfo?` | null | The icon to display using custom CSS classes for external icon libraries (e.g., FontAwesome, Bootstrap Icons). Takes precedence over IconName when both are set. |
| IconLocation | `BitIconLocation` | BitIconLocation.Right | TimePicker icon location. |
| IconName | `string?` | Clock | The name of the icon from the built-in Fluent UI icons. For external icon libraries, use Icon instead. |
| IconTemplate | `RenderFragment?` | null | Custom TimePicker icon template. |
| InvalidErrorMessage | `string?` | null | The custom validation error message for the invalid value. |
| InvertMouseWheel | `bool` | false | Reverses the direction the mouse wheel moves the dial in. |
| IsOpen | `bool` | false | Whether or not this TimePicker is open. Supports two-way binding. |
| Label | `string?` | null | Label for the TimePicker. |
| LabelTemplate | `RenderFragment?` | null | Used to customize the label for the TimePicker. |
| Landscape | `bool` | false | Lays the clock out beside its toolbar instead of under it, from the small breakpoint up. |
| MaxTime | `TimeSpan?` | null | The latest time that can be selected. Later hours, and the minutes past it inside its own hour, are dimmed on the dial and refused by the pointer, the keyboard and the text input. |
| MinTime | `TimeSpan?` | null | The earliest time that can be selected. Earlier hours, and the minutes before it inside its own hour, are dimmed on the dial and refused by the pointer, the keyboard and the text input. |
| MinuteButtonTitle | `string` | Select minute | The title (and accessible name) of the button that switches the dial to the minutes. |
| MinuteStep | `int` | 1 | The step, in minutes, the dial and the keyboard move the minute by. A step greater than 1 lays a grid over the hour that the pick snaps to, starting at the minute of MinTime and at the top of the hour where there is none. |
| NoMouseWheel | `bool` | false | Disables moving the dial with the mouse wheel entirely. By default the wheel moves it by one step while scrolled over the focused dial with the Shift key held down. |
| NowButtonText | `string` | Now | The text of the button that sets the TimePicker to the current time. |
| OnClear | `EventCallback` | | Callback for when the value is cleared using the clear button. |
| OnClick | `EventCallback` | | Callback for when clicking on TimePicker input. |
| OnClose | `EventCallback` | | Callback for when the callout of the TimePicker closes. |
| OnFocus | `EventCallback` | | Callback for when the TimePicker input receives focus. Unlike OnFocusIn it does not bubble, so it is the one to use when only the input itself receiving focus is of interest. |
| OnFocusIn | `EventCallback` | | Callback for when focus moves into the TimePicker input or any of its descendants, since unlike OnFocus it bubbles. |
| OnFocusOut | `EventCallback` | | Callback for when focus moves out of the TimePicker input. |
| OnOpen | `EventCallback` | | Callback for when the callout of the TimePicker opens. |
| OnSelectTime | `EventCallback<TimeSpan?>` | | Callback for when the selected time changes. |
| OnViewChange | `EventCallback<BitCircularTimePickerView>` | | Callback for when the dial switches between the hours, the minutes and the seconds. |
| OutOfRangeErrorMessage | `string?` | null | The custom validation error message for a time entered as text that falls outside of MinTime and MaxTime. Text that does not read as a time at all reports InvalidErrorMessage instead. |
| Placeholder | `string?` | null | Placeholder text for the TimePicker. |
| Responsive | `bool` | false | Enables the responsive mode in small screens. |
| SecondButtonTitle | `string` | Select second | The title (and accessible name) of the button that switches the dial to the seconds. |
| SecondStep | `int` | 1 | The step, in seconds, the dial and the keyboard move the second by. A step greater than 1 lays a grid over the minute that the pick snaps to, starting at the second of MinTime and at the top of the minute where there is none. |
| ShowClearButton | `bool` | false | Renders a button that clears the value of the TimePicker under the clock. |
| ShowCloseButton | `bool` | false | Whether the TimePicker's close button should be shown or not. |
| ShowNowButton | `bool` | false | Renders a button that sets the TimePicker to the current time under the clock, snapped to the steps and clamped into the selectable range. |
| ShowSeconds | `bool` | false | Adds the seconds to the picker: a third ring the dial moves on to after the minute, a third part in the toolbar, and the seconds of the value kept instead of zeroed. |
| Size | `BitSize?` | null | The size of the TimePicker. |
| Standalone | `bool` | false | Whether the TimePicker is rendered standalone or with the input component and callout. |
| StartingValue | `TimeSpan?` | null | The time an empty TimePicker starts from, instead of midnight. It is not a value: an untouched picker stays empty and the dial shows nothing selected - it is only where the first change lands. |
| StartView | `BitCircularTimePickerView` | BitCircularTimePickerView.Hour | The part of the time the clock starts on when the picker opens. The EditMode wins over it, and so does a Second start view on a picker that does not show the seconds. |
| Styles | `BitCircularTimePickerClassStyles` | null | Custom CSS styles for different parts of the TimePicker. |
| TimeFormat | `BitTimeFormat` | BitTimeFormat.TwentyFourHours | The time format of the time-picker, 24H or 12H. |
| Underlined | `bool` | false | Whether or not the Text field of the TimePicker is underlined. |
| ValueFormat | `string?` | null | The format of the time in the TimePicker like "HH:mm". Left unset it follows the time pattern of the culture, rewritten into the TimeFormat, extended with the seconds where ShowSeconds is set and padded with the leading zeros. |
| DefaultValue | `TValue?` | null | The default value of the input to be used in uncontrolled mode (i.e. when the Value is not bound), typically used alongside the OnChange callback. |
| DisplayName | `string?` | null | Gets or sets the display name for this field. |
| InputHtmlAttributes | `IReadOnlyDictionary<string, object>?` | null | Gets or sets a collection of additional attributes that will be applied to the created element. |
| Name | `string?` | null | Gets or sets the name of the element. Allows access by name from the associated form. |
| NoValidate | `bool` | false | Disables the validation of the input. |
| OnChange | `EventCallback<TValue?>` | | Callback for when the input value changes. |
| ReadOnly | `bool` | false | Makes the input read-only. |
| Required | `bool` | false | Makes the input required. |
| Value | `TValue?` | null | Gets or sets the value of the input. This should be used with two-way binding. |
| AriaLabel | `string?` | null | Gets or sets the accessible label for the component, used by assistive technologies. |
| Class | `string?` | null | Gets or sets the CSS class name(s) to apply to the rendered element. |
| Dir | `BitDir?` | null | Gets or sets the text directionality for the component's content. |
| ForceAnimation | `bool` | false | Gets or sets a value indicating whether the component's animations play at their full duration even when reduced motion is requested. |
| HtmlAttributes | `Dictionary<string, object>` | new Dictionary<string, object>() | Captures additional HTML attributes to be applied to the rendered element, in addition to the component's parameters. |
| Id | `string?` | null | Gets or sets the unique identifier for the component's root element. |
| IsEnabled | `bool` | true | Gets or sets a value indicating whether the component is enabled and can respond to user interaction. |
| Style | `string?` | null | Gets or sets the CSS style string to apply to the rendered element. |
| TabIndex | `string?` | null | Gets or sets the tab order index for the component when navigating with the keyboard. |
| Visibility | `BitVisibility` | BitVisibility.Visible | Gets or sets the visibility state (visible, hidden, or collapsed) of the component. |
## Public Members
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| InputId | `string?` | | The id of the input element of the TimePicker. |
| View | `BitCircularTimePickerView` | | The part of the time the clock is currently editing. |
| OpenCallout | `Task OpenCallout()` | | Opens the callout of the TimePicker, doing nothing when it is already open or when the picker is standalone and has no callout to open. |
| DismissCallout | `Task DismissCallout()` | | Closes the callout of the TimePicker. |
| SwitchView | `Task SwitchView(BitCircularTimePickerView view)` | | Switches the dial to the hours, the minutes or the seconds, as far as the EditMode and ShowSeconds allow it. |
| InputElement | `ElementReference` | | The ElementReference of the input element. |
| FocusAsync() | `() => ValueTask` | | Gives focus to the input element. |
| FocusAsync(bool preventScroll) | `(bool preventScroll) => ValueTask` | | Gives focus to the input element. |
| UniqueId | `Guid` | Guid.NewGuid() | Gets the readonly unique identifier for the component's root element, assigned when the component instance is constructed. |
| RootElement | `ElementReference` | | Gets the reference to the root HTML element associated with this component. |
## Enums
### BitVisibility Enum
| Name | Value | Description |
| :--- | :--- | :---------- |
| Visible | 0 | Show content of the component. |
| Hidden | 1 | Hide content of the component,though the space it takes on the page remains. |
| Collapsed | 2 | Hide content of the component,though the space it takes on the page gone. |
### BitIconLocation Enum
| Name | Value | Description |
| :--- | :--- | :---------- |
| Left | 0 | Show the icon at the left side. |
| Right | 1 | Show the icon at the right side. |
### BitCircularTimePickerEditMode Enum
| Name | Value | Description |
| :--- | :--- | :---------- |
| Normal | 0 | Every part the picker shows can be edited, and settling one moves the dial on to the next. |
| OnlyMinutes | 1 | Only the minute can be edited; the rest of the current value is kept as it is. |
| OnlyHours | 2 | Only the hour can be edited; the rest of the current value is kept as it is. |
| OnlySeconds | 3 | Only the second can be edited; the rest of the current value is kept as it is. The picker deals in seconds in this mode whether or not ShowSeconds is set. |
### BitCircularTimePickerView Enum
| Name | Value | Description |
| :--- | :--- | :---------- |
| Hour | 0 | The dial selects the hour. |
| Minute | 1 | The dial selects the minute. |
| Second | 2 | The dial selects the second, which only a picker that shows the seconds ever moves on to. |
### BitTimeFormat Enum
| Name | Value | Description |
| :--- | :--- | :---------- |
| TwentyFourHours | 0 | Show time pickers in 24 hours format. |
| TwelveHours | 1 | Show time pickers in 12 hours format. |
### BitSize Enum
| Name | Value | Description |
| :--- | :--- | :---------- |
| Small | 0 | The small size. |
| Medium | 1 | The medium size. |
| Large | 2 | The large size. |
### BitColor Enum
| Name | Value | Description |
| :--- | :--- | :---------- |
| Primary | 0 | Primary general color. |
| Secondary | 1 | Secondary general color. |
| Tertiary | 2 | Tertiary general color. |
| Info | 3 | Info general color. |
| Success | 4 | Success general color. |
| Warning | 5 | Warning general color. |
| SevereWarning | 6 | SevereWarning general color. |
| Error | 7 | Error general color. |
| PrimaryBackground | 8 | Primary background color. |
| SecondaryBackground | 9 | Secondary background color. |
| TertiaryBackground | 10 | Tertiary background color. |
| PrimaryForeground | 11 | Primary foreground color. |
| SecondaryForeground | 12 | Secondary foreground color. |
| TertiaryForeground | 13 | Tertiary foreground color. |
| PrimaryBorder | 14 | Primary border color. |
| SecondaryBorder | 15 | Secondary border color. |
| TertiaryBorder | 16 | Tertiary border color. |
### BitVisibility Enum
| Name | Value | Description |
| :--- | :--- | :---------- |
| Visible | 0 | The content of the component is visible. |
| Hidden | 1 | The content of the component is hidden, but the space it takes on the page remains (visibility:hidden). |
| Collapsed | 2 | The component is hidden (display:none). |
### BitDir Enum
| Name | Value | Description |
| :--- | :--- | :---------- |
| Ltr | 0 | Ltr (left to right) is to be used for languages that are written from the left to the right (like English). |
| Rtl | 1 | Rtl (right to left) is to be used for languages that are written from the right to the left (like Arabic). |
| Auto | 2 | Auto lets the user agent decide. It uses a basic algorithm as it parses the characters inside the element until it finds a character with a strong directionality, then applies that directionality to the whole element. |
## Sub Classes
### BitCircularTimePickerClassStyles Properties
| Name | Type | Default Value | Description |
| :--- | :--- | :------------ | :---------- |
| Root | `string?` | null | Custom CSS classes/styles for the root element of the BitCircularTimePicker. |
| Focused | `string?` | null | Custom CSS classes/styles for the focused state of the BitCircularTimePicker. |
| Label | `string?` | null | Custom CSS classes/styles for the Label of the BitCircularTimePicker. |
| InputWrapper | `string?` | null | Custom CSS classes/styles for the input wrapper of the BitCircularTimePicker. |
| InputContainer | `string?` | null | Custom CSS classes/styles for the input container of the BitCircularTimePicker. |
| Input | `string?` | null | Custom CSS classes/styles for the input of the BitCircularTimePicker. |
| Icon | `string?` | null | Custom CSS classes/styles for the icon of the BitCircularTimePicker. |
| Overlay | `string?` | null | Custom CSS classes/styles for the overlay of the BitCircularTimePicker. |
| Callout | `string?` | null | Custom CSS classes/styles for the callout of the BitCircularTimePicker. |
| CalloutContainer | `string?` | null | Custom CSS classes/styles for the callout container of the BitCircularTimePicker. |
| Toolbar | `string?` | null | Custom CSS classes/styles for the toolbar of the BitCircularTimePicker. |
| Body | `string?` | null | Custom CSS classes/styles for the body of the BitCircularTimePicker - everything under the toolbar: the clock, the AM/PM pair when it is placed there, and the row of actions. |
| HourMinuteContainer | `string?` | null | Custom CSS classes/styles for the hour and minute container of the BitCircularTimePicker. |
| HourButton | `string?` | null | Custom CSS classes/styles for the hour button of the BitCircularTimePicker. |
| MinuteButton | `string?` | null | Custom CSS classes/styles for the minute button of the BitCircularTimePicker. |
| SecondButton | `string?` | null | Custom CSS classes/styles for the second button of the BitCircularTimePicker. |
| HourMinuteSeparator | `string?` | null | Custom CSS classes/styles for the hour minute separator of the BitCircularTimePicker. |
| HourMinuteText | `string?` | null | Custom CSS classes/styles for the hour/minute text rendered in the single-part edit modes of the BitCircularTimePicker. |
| AmPmContainer | `string?` | null | Custom CSS classes/styles for the AM/PM container of the BitCircularTimePicker. |
| AmButton | `string?` | null | Custom CSS classes/styles for the AM button of the BitCircularTimePicker. |
| PmButton | `string?` | null | Custom CSS classes/styles for the PM button of the BitCircularTimePicker. |
| SelectedButtons | `string?` | null | Custom CSS classes/styles for the selected buttons of the BitCircularTimePicker. |
| ClockContainer | `string?` | null | Custom CSS classes/styles for the clock container of the BitCircularTimePicker. |
| ClockFace | `string?` | null | Custom CSS classes/styles for the clock face of the BitCircularTimePicker. |
| ClockPin | `string?` | null | Custom CSS classes/styles for the clock pin of the BitCircularTimePicker. |
| ClockNumber | `string?` | null | Custom CSS classes/styles for the clock number of the BitCircularTimePicker. |
| ClockSelectedNumber | `string?` | null | Custom CSS classes/styles for the clock selected number of the BitCircularTimePicker. |
| ClockDisabledNumber | `string?` | null | Custom CSS classes/styles for a clock number that cannot be selected, because of the time bounds, the steps or the allowed-value predicates. |
| ClockPointer | `string?` | null | Custom CSS classes/styles for the clock pointer of the BitCircularTimePicker. |
| ClockPointerThumb | `string?` | null | Custom CSS classes/styles for the clock pointer thumb of the BitCircularTimePicker. |
| ClockPointerThumbMinute | `string?` | null | Custom CSS classes/styles for the clock pointer thumb of the BitCircularTimePicker when it does not rest on a number of the dial - between two marks, or on a part of the time that has not been set yet. |
| Actions | `string?` | null | Custom CSS classes/styles for the row holding the "now" and "clear" buttons of the BitCircularTimePicker. |
| NowButton | `string?` | null | Custom CSS classes/styles for the button that sets the BitCircularTimePicker to the current time. |
| ClearButton | `string?` | null | Custom CSS classes/styles for the button that clears the value of the BitCircularTimePicker. |
| CloseButton | `string?` | null | Custom CSS classes/styles for the close button of the BitCircularTimePicker. |
| CloseButtonIcon | `string?` | null | Custom CSS classes/styles for the close button icon of the BitCircularTimePicker. |
## Examples
\n**Basic**:
```razor
```
\n**Standalone**:
```razor
```
\n**Time format**:
```razor
```
\n**Seconds**:
```razor
```
\n**Selectable range**:
```razor
```
\n**Picker actions**:
```razor
```
\n**Open state**:
```razor
@(isCalloutOpen ? "Close" : "Open") from outside
```
```csharp
private bool isCalloutOpen;
```
\n**Text input**:
```razor
```
\n**Value format**:
```razor
```
\n**Binding**:
```razor
```
```csharp
// The short time pattern of a culture spells the hour with an "h" where its readers expect a
// 12-hour clock and with an "H" where they expect a 24-hour one. Only the format tokens of the
// pattern say so: the "HH 'h' mm" of fr-CA carries an h of its own, as a quoted literal that is
// text of the culture rather than an hour token.
private static BitTimeFormat GetTimeFormatOf(CultureInfo culture)
{
var pattern = culture.DateTimeFormat.ShortTimePattern;
char? quote = null;
for (var i = 0; i < pattern.Length; i++)
{
var current = pattern[i];
// An escaped character stands for itself, so it is skipped along with the backslash escaping it.
if (current == '\\')
{
i++;
continue;
}
if (quote.HasValue)
{
if (current == quote) quote = null;
continue;
}
if (current is '\'' or '"')
{
quote = current;
continue;
}
if (current == 'h') return BitTimeFormat.TwelveHours;
}
return BitTimeFormat.TwentyFourHours;
}
```
\n**ReadOnly**:
```razor
```
```csharp
private TimeSpan? readOnlyTime = new(2, 50, 0);
```
\n**Appearance**:
```razor
```
\n**Templates**:
```razor
Custom label
```
```csharp
private BitCircularTimePicker circularTimePicker = default!;
private async Task OpenCallout()
{
await circularTimePicker.OpenCallout();
}
```
\n**Responsive**:
```razor
```
\n**Keyboard & accessibility**:
```razor
```
\n**Validation**:
```razor
Submit
@if (string.IsNullOrEmpty(successMessage) is false)
{
@successMessage
}
```
```csharp
public class FormValidationCircularTimePickerModel
{
[Required]
public TimeSpan? Time { get; set; }
}
private string successMessage = string.Empty;
private FormValidationCircularTimePickerModel formValidationCircularTimePickerModel = new();
private async Task HandleValidSubmit()
{
successMessage = "Form Submitted Successfully!";
await Task.Delay(3000);
successMessage = string.Empty;
StateHasChanged();
}
private void HandleInvalidSubmit()
{
successMessage = string.Empty;
}
```
\n**Events**:
```razor
eventLogs = [];
private void LogOpen() => Log("OnOpen");
private void LogClose() => Log("OnClose");
private void LogClick() => Log("OnClick");
private void LogFocusIn() => Log("OnFocusIn");
private void LogFocusOut() => Log("OnFocusOut");
private void LogViewChange(BitCircularTimePickerView view) => Log($"OnViewChange: {view}");
private void LogSelectTime(TimeSpan? time) => Log($"OnSelectTime: {time}");
private void LogChange(TimeSpan? time) => Log($"OnChange: {time}");
private void Log(string message)
{
eventLogs.Insert(0, message);
if (eventLogs.Count > 8)
{
eventLogs.RemoveRange(8, eventLogs.Count - 8);
}
}
```
\n**Landscape**:
```razor
```
\n**Color**:
```razor
```
\n**External Icons**:
```razor
```
\n**Size**:
```razor
```
\n**Style & Class**:
```razor
```
```csharp
private TimeSpan? classesValue;
```
\n**RTL**:
```razor
```
Selected time: @secondsTime.ToString()
```
```csharp
private TimeSpan? secondsTime = new(14, 5, 30);
```
\n**Edit mode & views**:
```razor
Last view change: @(changedView?.ToString() ?? "-")
```
```csharp
private BitCircularTimePickerView? changedView;
```
\n**Steps**:
```razor
Selected time: @selectedTime.ToString()
Changed time: @changedTime.ToString()
```
```csharp
private TimeSpan? selectedTime = new(5, 12, 0);
private TimeSpan? changedTime;
```
\n**Culture**:
```razor
Pick a time
Times are local
@foreach (var log in eventLogs)
{
```
```csharp
private readonly List@log
}