Skip to content

Inputs

OtpInput

Bit.BlazorUI

A one-time code entered as a row of single character boxes bound to one string. Focus advances as you type, the keyboard edits the code like a single field, and a pasted or SMS-filled code is cleaned up and spread over the boxes. It filters, folds and normalizes what it accepts, reports what it rejects, and carries the busy and error states of the round trip that follows.

Usage

Every example is live. Open its code to see exactly what produced the component running underneath.

Basic

Length boxes (5 by default) bound to one string. Typing advances the focus. Backspace clears the box it is pressed in - on an empty box, the one before it - Delete clears in place, and the arrows, Home and End walk the code.

AutoFocus lands in the first empty box. AutoShift pulls the rest of the code along instead of leaving a hole. BlurOnFill drops the focus - and a phone's keyboard - on the last character. Sequential pulls a click or a paste past the first empty box back to it.


Basic




Length = 4




Disabled




ReadOnly




AutoFocus




AutoShift




BlurOnFill




Sequential (try clicking the last box)

Label & description

Label is a real label bound to the first box and names the group of boxes. Required adds the asterisk and marks every box required.

Description is the helper text under the boxes - where the code was sent, how long it is valid. The group references it, so it is announced once rather than at every box. The templates take markup instead, such as a "resend" link.


Label:






Required:






LabelTemplate:






Description:


We sent a 6 digit code to +1 555 0100. It stays valid for 10 minutes.




DescriptionTemplate:


Didn't get it? Send it again

Type & keyboard

Type picks the accepted characters and the phone keyboard: Number accepts digits only, typed or pasted, Password masks with the browser's bullet. Number, Email and Url render as text inputs - their native elements would add spin buttons or a validation one character never passes.

InputMode asks for another keyboard without changing what is accepted, e.g. the larger telephone keypad for digits. NormalizeDigits folds Persian, Arabic and other digits into ASCII.









Value:
Try pasting ۱۲۳۴۵۶ or ١٢٣٤٥٦.

Mask & placeholder

Placeholder is the hint of an empty box; one exactly Length long is spread one character per box. Mask is what a filled box shows instead of its character - any text, even an emoji. Neither touches the value, and a masked code is kept off the clipboard.











Value:

Pattern & casing

Pattern is a regular expression every character has to match: a non-matching keystroke is rejected, a pasted code only loses its non-matching characters. Uppercase and Lowercase fold the case first, so a restricted pattern still accepts either case.







Separator

Separator draws text between the boxes; SeparatorInterval sets how many boxes a group holds (3 renders 123-456). SeparatorTemplate takes markup, with the index of the next box as its context. Separators are decoration only: never focused, announced or part of the value.









Variant

How much frame a box carries: Outline (the default) a full rule, Fill a surface and no rule, Text only an underline - its focus indicator is an underline too.





Layout

Vertical stacks the boxes, Reversed flips their order; the arrow keys follow the layout, while Home and End always reach the first and last character. FullWidth stretches the row across its container and shares the width between the boxes.










Merged

Merged glues the boxes of each group into one field: no gaps, shared rules drawn once, rounding only at the ends. The groups are the ones the Separator makes, and it works with every Variant, Vertical and Reversed.











Autofill, paste & copy

A code arriving in one go - autocomplete="one-time-code", the WebOTP API or a paste - is cleaned up before it lands: whitespace, invisible characters and whatever Type or Pattern rejects are dropped. A full-length code starts at the first box wherever it was pasted.

PasteTransformer runs over the whole chunk first, to pull a code of letters out of the message around it; an empty result rejects the paste. Copying from any box copies the whole code, a cut clears it. NoSmsAutoFill turns SMS and password-manager autofill off.

Try pasting 123 456, 12-34-56 or your code is 123456:

Value:


Try pasting your code is A1B2C3, do not share it:

Value:


Binding

The value is the whole code as one string. Value alone is one-way, bind-Value two-way; null or an empty string clears the boxes.



Events

OnFill fires once per completed code - the place to submit it. OnInvalid fires when a keystroke or a paste is rejected in full, with the rejected text and the box index. The rest forward each box's DOM events along with its index.

OnChange value:


OnFill value:


Rejected:
Input index:


Focus type:
Input index:


Focus type:
Input index:


Value:
Input index:


Key & Code: [] []
Input index:


Focus type:
Input index:

Public API

FocusAsync focuses a box (index clamped), BlurAsync drops the focus, Clear empties the code, InputElements exposes the boxes. All are safe before the first render and do nothing when there is nothing to do.


Validation & auto submit

Works with EditForm and data annotations like any Blazor input, marking the boxes aria-invalid on a failing validation. AutoSubmit submits the enclosing form the moment the code is complete, validation included. Name posts the whole code as one field.





Loading & invalid

The round trip after OnFill. IsLoading draws a bar, holds the code still and marks the group aria-busy while the server checks it. Invalid paints the error state a validator cannot see - an expired or wrong code. While either is on, the Description is announced through a live region.

Enter the 6 digit code we sent you. Try 123456.

Accessibility

The boxes form a group named by Label (or AriaLabel) and described by Description; each box is announced by position, 1 of 6. InputAriaLabelFormat localizes it - {0} is the position, {1} the Length. SingleTabStop makes the whole code one tab stop.

Separators are hidden from screen readers, IsLoading and Invalid are announced as they happen, the boxes clear the 24px target size, and an autofilled box keeps the contrast of the theme.









Enter the code from the text message we sent to +1 555 0100.

Cascading parameters

BitParams hands a BitOtpInputParams to every otp input below it - the place for rules the server decides, such as Length, Type and PasteTransformer. They are defaults: a parameter set on the component itself wins. Value, DefaultValue and Name are never cascaded.




Accent

Accent colors the focused box's border and ring and the IsLoading bar. The error state always wins over it.















Size

Size scales the boxes and their text together, matching the control heights of the theme.





Style & Class

Style and Class reach the root; Styles and Classes reach every part, plus the Focused and Filled state slots of each box.


Component's Style & Class:





Styles & Classes:

Every part of the component has a slot of its own.

Every part of the component has a slot of its own.


The public CSS variables inherit, so one set on :root or an ancestor restyles every otp input below it, and one on Style restyles a single instance. The filled pair paints the boxes that hold a character.





Set once on an ancestor, inherited by every otp input inside it:


RTL

Right-to-left lays the boxes out from the right and swaps the arrow keys with them. The value keeps its logical order.






CSS variables

The public custom properties this component reads off its root, for what no parameter covers.

Every variable is read with a fallback and never declared by the component, so it inherits like any other custom property: set one on :root (or in a [bit-theme] block) to restyle every instance, on any ancestor to restyle the ones inside it, or on the Style of one instance to restyle that one alone. Leave a variable unset and the component falls back to the theme token beside it.

BitOtpInput CSS variables

Name Default value Description
--bit-OtpInput-gap 0.625rem Room between the inputs. Merged closes it to 0 whatever this holds.
--bit-OtpInput-input-size --bit-siz-ctrl-sm / --bit-siz-ctrl-md / --bit-siz-ctrl-lg, per Size Width and height of every input, which is a square of the control height of its size class. FullWidth overrides the width alone.
--bit-OtpInput-input-width --bit-OtpInput-input-size Width of an input on its own, for a box wider than it is tall.
--bit-OtpInput-input-height --bit-OtpInput-input-size Height of an input on its own.
--bit-OtpInput-font-family --bit-tpg-font-family Typeface of the whole component, which is where a tabular or monospaced face for the code is set - the one piece of text in a form that is read character by character.
--bit-OtpInput-font-size --bit-tpg-fs-xs / --bit-tpg-fs-sm / --bit-tpg-fs-md, per Size Size of the code, inherited by the label and the placeholder.
--bit-OtpInput-label-font-size --bit-OtpInput-font-size Size of the label above the inputs, which follows the size of the code unless it is set on its own.
--bit-OtpInput-label-font-weight --bit-tpg-field-label-font-weight Weight of the label above the inputs.
--bit-OtpInput-description-font-size --bit-tpg-fs-2xs / --bit-tpg-fs-xs / --bit-tpg-fs-sm, per Size Size of the helper text under the inputs, one step of the type ramp below the code.
--bit-OtpInput-font-weight --bit-tpg-fw-regular Weight of the character inside an input.
--bit-OtpInput-radius --bit-shp-radius-control Corner radius of an input, and of the two ends of every group while Merged is on. The Text variant squares them off whatever this holds.
--bit-OtpInput-border-width --bit-shp-border-width Thickness of an input's rule, and with it the overlap that glues two Merged inputs together.
--bit-OtpInput-color --bit-clr-fg-pri Color of the typed character.
--bit-OtpInput-background Per Variant: --bit-clr-bg-pri (Outline), --bit-clr-bg-sec (Fill), transparent (Text) Input background at rest, and the fallback of the hover and filled backgrounds below.
--bit-OtpInput-hover-background Per Variant: the rest background (Outline, Text), --bit-clr-bg-sec-hover (Fill) Input background while hovered, on an input that is neither disabled nor read-only.
--bit-OtpInput-border-color Per Variant: --bit-clr-brd-pri (Outline, Text), transparent (Fill) Input rule at rest, and the fallback of the hover and filled rules below.
--bit-OtpInput-hover-border-color Per Variant: --bit-clr-brd-pri-hover (Outline, Text), the rest rule (Fill) Input rule while hovered.
--bit-OtpInput-filled-background --bit-OtpInput-background Background of an input that already holds a character, which is what turns the row into its own progress indicator. It has no parameter behind it.
--bit-OtpInput-filled-border-color --bit-OtpInput-border-color Rule of an input that already holds a character.
--bit-OtpInput-focus-border-color The Accent role's main color Input rule while focused.
--bit-OtpInput-focus-color The Accent role's focus color Color of the keyboard focus ring.
--bit-OtpInput-placeholder-color --bit-clr-fg-ter Hint character of an empty input.
--bit-OtpInput-label-color --bit-clr-fg-pri Label above the inputs.
--bit-OtpInput-description-color --bit-clr-fg-sec Helper text under the inputs, outside the error state.
--bit-OtpInput-separator-color --bit-clr-fg-sec Text drawn between the groups of the code.
--bit-OtpInput-invalid-color --bit-clr-err Input rule, helper text and loading bar while Invalid is on or a validation is failing.
--bit-OtpInput-invalid-focus-color --bit-clr-err-focus Focus ring color in the error state.
--bit-OtpInput-disabled-color --bit-clr-fg-dis Character, placeholder, label, helper text, separator and loading bar when Disabled is true.
--bit-OtpInput-disabled-background --bit-clr-bg-dis Input background when Disabled is true.
--bit-OtpInput-disabled-border-color --bit-clr-brd-dis Input rule when Disabled is true.
--bit-OtpInput-loader-color The Accent role's main color The sweep of the bar drawn while IsLoading is on. The error and disabled states paint it with their own color instead.
--bit-OtpInput-loader-background --bit-clr-bg-sec The track the sweep of the loading bar travels along.
--bit-OtpInput-loader-height --bit-siz-track-sm Thickness of the loading bar.

API

Every parameter, public member, sub-class and enum this component exposes.

BitOtpInput parameters

Name Type Default value Description
Accent BitColor? null The color of the focused input's border and focus ring, and of the loading bar. The error state wins over it.
AutoFocus bool false Focuses the first empty input on the first render that finds the component enabled.
AutoShift bool false Shifts the rest of the code one input back when a character is cleared with Backspace or Delete, instead of leaving a hole.
AutoSubmit bool false Submits the enclosing form (a plain form or an EditForm) right after OnFill, the way pressing Enter would: the form still validates first. Nothing happens outside of a form.
BlurOnFill bool false Removes the focus from the inputs once the code is complete, which dismisses a phone's virtual keyboard.
Classes BitOtpInputClassStyles? null Custom CSS classes for different parts of the BitOtpInput.
Description string? null Helper text under the inputs, referenced by the group's aria-describedby. While Invalid or IsLoading is on it is also announced through a live region.
DescriptionTemplate RenderFragment? null Custom template for the helper text, taking precedence over Description. It is described the same way but never copied into the live region.
FullWidth bool false Stretches the row across its container and shares the width evenly between the inputs. The height stays the one of the Size.
InputAriaLabelFormat string? null Composite format of each input's aria-label: {0} is the one based position and {1} the Length. Defaults to "{0} of {1}".
InputMode BitInputMode? null The inputmode attribute of the inputs, which picks the virtual keyboard without changing the accepted characters. Defaults to the one the Type implies.
Invalid bool false Paints the error state and sets aria-invalid without an EditContext, e.g. for a code the server rejected. A failing validation shows the same state on its own.
IsLoading bool false The busy state of a submitted code: draws a progress bar, marks the group aria-busy, announces the Description and holds the code still like ReadOnly. Clear is not blocked by it.
Label string? null Label displayed above the inputs, bound to the first input and naming the group of inputs.
LabelTemplate RenderFragment? null Custom template for the label displayed above the inputs, taking precedence over Label.
Length int 5 The number of inputs, which is the length of the code. Values below 1 are treated as 1.
Lowercase bool false Converts every character to lower case before the Pattern is applied. Uppercase wins when both are set.
Mask string? null Text shown in place of every filled input's character. The value stays the typed code, and a masked code is kept off the clipboard.
Merged bool false Glues the inputs of each group (the ones the Separator makes) into a single field with rounding only at its ends.
NormalizeDigits bool false Converts the digits of other numbering systems (Persian, Arabic-Indic, full width, ...) to ASCII before the Type and the Pattern are applied.
NoSmsAutoFill bool false Turns off the WebOTP SMS auto fill, the one-time-code autocomplete and the password managers' autofill.
OnFill EventCallback<string?> Callback for when all of the inputs are filled, raised once per completed code.
OnFocusIn EventCallback<(FocusEventArgs Event, int Index)> onfocusin event callback for each input, with the index of the input.
OnFocusOut EventCallback<(FocusEventArgs Event, int Index)> onfocusout event callback for each input, with the index of the input.
OnInput EventCallback<(ChangeEventArgs Event, int Index)> oninput event callback for each input, with the index of the input.
OnInvalid EventCallback<(string Value, int Index)> Callback for when a keystroke, paste or auto fill is rejected in full by the Type, the Pattern or the PasteTransformer, with the rejected text and the index of the input. A paste that only loses some characters does not raise it.
OnKeyDown EventCallback<(KeyboardEventArgs Event, int Index)> onkeydown event callback for each input, with the index of the input.
OnPaste EventCallback<(ClipboardEventArgs Event, int Index)> onpaste event callback for each input, with the index of the input.
PasteTransformer Func<string, string>? null Applied to a pasted or auto filled chunk before it is filtered, e.g. to pull the code out of the message around it. An empty result rejects the chunk; an exception leaves it untouched. Not applied to a single typed character.
Pattern string? null A regular expression every single character has to match. Non-matching characters are rejected when typed and dropped when pasted; an invalid expression is ignored.
Placeholder string? null Hint text of the empty inputs. A string exactly Length long is spread one character per input; any other is shown in every input.
Reversed bool false Renders the inputs in the opposite order. The arrow keys follow.
Separator string? null Text rendered between the groups of inputs. It is hidden from assistive technologies and never part of the value.
SeparatorInterval int 1 The number of inputs in each group the Separator is rendered between, e.g. 3 for 123-456. Values below 1 are treated as 1.
SeparatorTemplate RenderFragment<int>? null Custom template rendered in place of the Separator text, with the zero based index of the next input as its context.
Sequential bool false Keeps the code free of holes: focusing, or pasting into, an input past the first empty one lands on that first empty input instead. A complete code is left editable anywhere.
SingleTabStop bool false Makes the whole component a single tab stop: only the first input is reachable with Tab.
Size BitSize? null The size of the inputs.
Styles BitOtpInputClassStyles? null Custom CSS styles for different parts of the BitOtpInput.
Type BitInputType? null Type of the inputs, deciding the accepted characters and the virtual keyboard. Number accepts digits only; Number, Email and Url render as text inputs.
Uppercase bool false Converts every character to upper case before the Pattern is applied.
Variant BitVariant? null The visual variant of the inputs: Outline (default), Fill or Text (underline only).
Vertical bool false Renders the inputs vertically. The arrow keys follow.

BitOtpInput public members

Name Type Default value Description
InputElements ElementReference[] The ElementReferences to the input elements of the BitOtpInput. The inherited InputElement is the first of them.
BlurAsync () => ValueTask Removes the focus from the input that holds it, dismissing a phone's virtual keyboard. Does nothing when the focus is elsewhere on the page.
Clear () => Task Clears all of the inputs and the value. Does nothing while the component is disabled or read-only.
FocusAsync (int index = 0) => ValueTask Focuses the input at the given index, clamped into range. The inherited FocusAsync() and FocusAsync(bool preventScroll) focus the first input. Does nothing before the first render.

BitInputBase parameters

Name Type Default value Description
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.

BitInputBase public members

Name Type Default value Description
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.

BitComponentBase parameters

Name Type Default value Description
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.
Disabled bool false Gets or sets a value indicating whether the component is disabled and cannot respond to user interaction.
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.
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.

BitComponentBase public members

Name Type Default value Description
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.

BitOtpInputClassStyles properties

Name Type Default value Description
Root string? null Custom CSS classes/styles for the root element of the otp input.
Label string? null Custom CSS classes/styles for the label of the otp input.
Description string? null Custom CSS classes/styles for the description (helper text) of the otp input.
InputsWrapper string? null Custom CSS classes/styles for the wrapper element of the inputs.
Input string? null Custom CSS classes/styles for each input in otp input.
Focused string? null Custom CSS classes/styles for the focused input in otp input.
Filled string? null Custom CSS classes/styles for each input that already holds a character in otp input.
Separator string? null Custom CSS classes/styles for the separator rendered between the inputs of the otp input.
Loader string? null Custom CSS classes/styles for the progress bar rendered under the inputs while the otp input is in the loading state.

BitSize enum

Name Value Description
Small 0 The small size.
Medium 1 The medium size.
Large 2 The large size.

BitInputType enum

Name Value Description
Text 0 The input expects text characters.
Password 1 The input expects password characters.
Number 2 The input expects number characters.
Email 3 The input expects email characters.
Tel 4 The input expects tel characters.
Url 5 The input expects url characters.

BitInputMode enum

Name Value Description
None 0 No virtual keyboard. For when the page implements its own keyboard input control.
Text 1 Standard input keyboard for the user's current locale.
Decimal 2 Fractional numeric input keyboard containing the digits and decimal separator for the user's locale.
Numeric 3 Numeric input keyboard, but only requires the digits 0–9.
Tel 4 A telephone keypad input, including the digits 0–9, the asterisk (*), and the pound (#) key.
Search 5 A virtual keyboard optimized for search input.
Email 6 A virtual keyboard optimized for entering email addresses.
Url 7 A keypad optimized for entering URLs.

BitVariant enum

Name Value Description
Fill 0 Fill styled variant.
Outline 1 Outline styled variant.
Text 2 Text styled variant.

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.

Feedback

Found a mistake, a gap, or something that could be clearer? Every page and every component is one click from its source.