Skip to content
Introducing AI Conversations: Natural Language Interaction for Your Apps! Learn More

TextEntry

A Material Design-inspired text entry control with an animated floating placeholder, customizable border styling, left/right tool slots, hint text for validation errors, and character count display.

  • NuGet downloads for Shiny.Maui.Controls
  • NuGet downloads for Shiny.Blazor.Controls
Frameworks
.NET MAUI
Blazor
TextEntry
  • Animated Floating Placeholder — Slides up and scales down when the field is focused or contains text. Returns to center when empty and unfocused.
  • Customizable Border — Configure border color, focused color, thickness, focused thickness, corner radius, and background color.
  • Tool Slots — Left and right tool areas for icons, text, or interactive buttons. Tools can be simple labels or self-contained components like ClearButtonTool.
  • Hint Text — Helper text below the field for instructions or validation errors. Automatically switches to error styling when HasError is true.
  • Character Count — Optional counter display showing current length vs. max length.
  • Input Masking — Declarative Mask property for formatted input (phone, credit card, date, SSN, ZIP). Raw digits in Text, formatted display in FormattedText.
  • Input Modes — Password masking, read-only, keyboard type selection, return type configuration.
  • Reusable Tools — Built-in ClearButtonTool (auto-shows/hides based on text content) and TextEntrySpeechToTextTool (voice input via Shiny.Speech, in the SpeechAddins package).
claude plugin marketplace add shinyorg/skills
claude plugin install shiny-client@shiny
BLE, GPS, Jobs, Notifications, Push, HTTP Transfers, OBD, Music, Health, DataSync — iOS, Android, Windows, MacOS, Linux, Web
claude plugin install shiny-maui@shiny
Shell, Contact Store
claude plugin install shiny-controls@shiny
TableView, BottomSheet, PillView, ImageViewer, Scheduler, Markdown, Mermaid Diagrams — MAUI and Blazor
claude plugin install shiny-mediator@shiny
Mediator/CQRS with middleware and source generators
claude plugin install shiny-data@shiny
DocumentDB and Spatial data libraries
claude plugin install shiny-aspire@shiny
Orleans and Gluetun Aspire integrations
claude plugin install shiny-extensions@shiny
DI, Stores, Reflector, Localization, Hosting modules
copilot plugin marketplace add https://github.com/shinyorg/skills
copilot plugin install shiny-client@shiny
BLE, GPS, Jobs, Notifications, Push, HTTP Transfers, OBD, Music, Health, DataSync — iOS, Android, Windows, MacOS, Linux, Web
copilot plugin install shiny-maui@shiny
Shell, Contact Store
copilot plugin install shiny-controls@shiny
TableView, BottomSheet, PillView, ImageViewer, Scheduler, Markdown, Mermaid Diagrams — MAUI and Blazor
copilot plugin install shiny-mediator@shiny
Mediator/CQRS with middleware and source generators
copilot plugin install shiny-data@shiny
DocumentDB and Spatial data libraries
copilot plugin install shiny-aspire@shiny
Orleans and Gluetun Aspire integrations
copilot plugin install shiny-extensions@shiny
DI, Stores, Reflector, Localization, Hosting modules
View Skills Repository
<shiny:TextEntry Placeholder="Email"
Text="{Binding Email, Mode=TwoWay}"
Keyboard="Email"
HasError="{Binding HasEmailError}"
HintText="{Binding EmailError}">
<shiny:ClearButtonTool />
</shiny:TextEntry>
<TextEntry Placeholder="Email"
@bind-Text="email"
HasError="@hasError"
HintText="@errorMessage">
<RightTools>
<TextEntryClearButton Text="@email" TextChanged="v => email = v" />
</RightTools>
</TextEntry>
PropertyTypeDefaultDescription
Textstring""Current text value (TwoWay)
Placeholderstring""Animated floating placeholder text
PlaceholderColorColor/stringGrey / #9CA3AFPlaceholder color when unfocused
FocusedPlaceholderColorColor/string#007AFFPlaceholder color when focused or floating
BorderColorColor/string#CCCCCCBorder color when unfocused
FocusedBorderColorColor/string#007AFFBorder color when focused
BorderThicknessdouble1Border thickness (unfocused)
FocusedBorderThicknessdouble2Border thickness (focused)
CornerRadiusCornerRadius/string8 / 8pxBorder corner radius
EntryBackgroundColorColor/stringTransparentBackground inside the border
FontSizedouble15Text and placeholder font size
FontFamilystring?null / inheritFont family
FontAttributesFontAttributesNoneBold/Italic (MAUI only)
TextColorColor/stringBlack / inheritInput text color
IsReadOnlyboolfalseRead-only mode
IsPasswordboolfalsePassword masking
ReturnTypeReturnTypeDefaultKeyboard return button (MAUI only)
KeyboardKeyboardDefaultKeyboard type (MAUI only)
MaxLengthintunlimitedMaximum character count
Maskstring?nullInput mask pattern (# = digit slot, others are auto-inserted literals)
FormattedTextstring""Read-only formatted display value when Mask is set
HintTextstring?nullHint/helper text below the field
HintColorColor/stringGrey / #9CA3AFHint text color
HasErrorboolfalseError state (changes border/hint to ErrorColor)
ErrorColorColor/string#DC3545Error state color
ShowCharacterCountboolfalseShow character count below the field
LeftToolsIList / RenderFragmentemptyLeft tool slot
RightToolsIList / RenderFragmentemptyRight tool slot (ContentProperty on MAUI)
TextChangedCommandICommand?nullText change command (MAUI only)
CompletedCommandICommand?nullReturn key command (MAUI only)

TextEntry supports left and right tool areas on both MAUI and Blazor. Tools are TextEntryTool subclass instances — on MAUI they’re declared in XAML, on Blazor they’re passed as List<TextEntryTool>.

ClearButtonTool — Automatically appears when text is non-empty and clears the field on tap/click. Available on both MAUI and Blazor.

<!-- MAUI -->
<shiny:TextEntry Placeholder="Search" Text="{Binding Query, Mode=TwoWay}">
<shiny:ClearButtonTool />
</shiny:TextEntry>
<!-- Blazor -->
<TextEntry Placeholder="Search" @bind-Text="query" RightTools="tools" />
@code {
string query = "";
List<TextEntryTool> tools = [new ClearButtonTool()];
}

TextEntrySpeechToTextTool (MAUI, requires Shiny.Maui.Controls.SpeechAddins) — Voice input tool that listens for speech via ISpeechToTextService and fills the entry text. Toggles listening state with visual feedback.

SpeechToTextTool (Blazor, requires Shiny.Blazor.Controls.SpeechAddins) — Voice input tool using the Web Speech API via JS interop.

<!-- MAUI -->
<shiny:TextEntry Placeholder="Amount">
<shiny:TextEntry.LeftTools>
<shiny:TextEntryTool Text="$" ToolColor="#059669" />
</shiny:TextEntry.LeftTools>
<shiny:ClearButtonTool />
</shiny:TextEntry>
<!-- Blazor -->
<TextEntry Placeholder="Amount" LeftTools="leftTools" RightTools="rightTools" />
@code {
List<TextEntryTool> leftTools = [new TextEntryTool { Text = "$", ToolColor = "#059669" }];
List<TextEntryTool> rightTools = [new ClearButtonTool()];
}

MAUI:

PropertyTypeDescription
IconImageSource?Tool icon
Textstring?Tool text label
ToolColorColorText/icon color
CommandICommand?Tap command
CommandParameterobject?Command parameter

Blazor:

PropertyTypeDescription
Iconstring?Icon text/emoji
Textstring?Tool text label
ToolColorstringCSS color
IsVisibleboolWhether the tool is shown (default: true)
ClickedAction?Click callback
CssClassstring?Additional CSS class

MAUI — Implement ITextEntryAwareTool on a TextEntryTool subclass:

public interface ITextEntryAwareTool
{
void Attach(TextEntry entry);
void Detach();
}

Blazor — Override lifecycle methods on TextEntryTool:

public class MyTool : TextEntryTool
{
public override void OnTextChanged(string? text) { /* react to text changes */ }
protected override void OnClick() { SetEntryText("new value"); }
}

Set Mask to automatically format input as the user types. The # character represents a digit slot; all other characters are literal separators inserted automatically.

When Mask is set:

  • Text always contains raw digits only (e.g., "5551234567")
  • FormattedText contains the display value (e.g., "(555) 123-4567")
  • Keyboard auto-sets to Numeric
  • Cursor position is managed automatically
  • Paste is handled gracefully (non-digits stripped, then reformatted)
<shiny:TextEntry Placeholder="Phone Number"
Mask="(###) ###-####"
Text="{Binding Phone, Mode=TwoWay}" />
<shiny:TextEntry Placeholder="Credit Card"
Mask="#### #### #### ####"
Text="{Binding CardNumber, Mode=TwoWay}" />
<shiny:TextEntry Placeholder="MM/DD/YYYY"
Mask="##/##/####"
Text="{Binding DateString, Mode=TwoWay}" />
<TextEntry Placeholder="Phone Number"
Mask="(###) ###-####"
@bind-Text="phone" />
@code {
string phone = ""; // Always raw digits, e.g. "5551234567"
}
<shiny:TextEntry Placeholder="Email"
Text="{Binding Email, Mode=TwoWay}"
Keyboard="Email"
HasError="{Binding HasEmailError}"
HintText="{Binding EmailError}"
ErrorColor="#DC3545">
<shiny:ClearButtonTool />
</shiny:TextEntry>

When HasError is true:

  • The border changes to ErrorColor
  • The floating placeholder changes to ErrorColor
  • The hint text displays in ErrorColor
<shiny:TextEntry Placeholder="Purple theme"
FocusedBorderColor="#7C3AED"
FocusedPlaceholderColor="#7C3AED"
FocusedBorderThickness="2"
CornerRadius="16"
EntryBackgroundColor="#F5F3FF">
<shiny:ClearButtonTool />
</shiny:TextEntry>