TextBox & TextArea
Single-line and multi-line text input with Material Design styling
Namespace: Beep.Skia.Controls — Inherits: MaterialControl → SkiaComponent
Table of Contents
Overview
The TextBox and TextArea controls provide Material Design 3.0 text input fields rendered entirely with SkiaSharp. TextBox handles single-line input (e.g., form fields, search boxes, labels) while TextArea extends it with multi-line editing, word wrap, and line count tracking. Both controls use SKCanvas for text rendering and integrate with the platform's keyboard input system via the InputManager.
Text fields follow the MD3 "Filled" and "Outlined" visual styles with animated label transitions, floating placeholder labels, error states, and helper text. The cursor is a blinking vertical line drawn by the control's render cycle. Text selection is drawn as a semi-transparent highlight rectangle.
TextBox Properties
| Property | Type | Description |
|---|---|---|
Text |
string |
The current text value. Setting this programmatically moves the cursor to the end unless CursorPosition is also set. |
Placeholder |
string |
Placeholder text shown when Text is empty. Rendered in OnSurfaceVariant color at 60% opacity. In MD3 style, the placeholder acts as a label that floats above the field when focused or populated. |
MaxLength |
int |
Maximum character count. Input beyond this limit is rejected. Default is 0 (unlimited). A character counter is displayed below the field when set. |
IsPassword |
bool |
When true, characters are rendered as bullets (•) instead of the actual text. A visibility toggle icon is drawn at the trailing edge. Default is false. |
IsReadOnly |
bool |
When true, the field cannot be edited but remains selectable for copy operations. The background is rendered in a muted state. Default is false. |
FieldStyle |
TextFieldStyle |
Enum: Filled (default) or Outlined. Filled has a filled background with an underline indicator. Outlined has a transparent background with a full border. |
IsFocused |
bool |
Read-only. Indicates whether the field has keyboard focus. When focused, the underline/outline is drawn in Primary color. |
CursorPosition |
int |
Zero-based index of the insertion cursor within Text. Setting this moves the cursor. Read to determine where the next typed character will be inserted. |
IsCursorVisible |
bool |
Read-only. Indicates whether the blinking cursor is currently shown (alternates on a timer). |
HelperText |
string |
Optional helper text displayed below the field in BodySmall typography. Used for hints or validation messages. |
HasError |
bool |
When true, the field renders in Error color (underline, outline, label) and the helper text color changes to Error. Default is false. |
LeadingIcon |
SKPath |
Optional icon drawn at the left side of the field. Icon color follows the field state. |
TrailingIcon |
SKPath |
Optional icon drawn at the right side. For IsPassword fields, a visibility toggle icon is automatically managed here. |
TextArea Properties
TextArea inherits all TextBox properties and adds multi-line support:
| Property | Type | Description |
|---|---|---|
LineCount |
int |
Read-only. The number of text lines, accounting for newline characters and word wrap. Updated on every text change. |
WordWrap |
bool |
When true (default), text automatically wraps at the field's width boundary. When false, horizontal scrolling is enabled. |
LineHeight |
float |
Vertical spacing between wrapped lines in logical pixels. Default is 20f. |
AcceptsReturn |
bool |
When true, the Enter key inserts a newline. When false, Enter triggers the default action or is ignored. Default is true. |
AcceptsTab |
bool |
When true, Tab inserts a tab character instead of moving focus. Default is false. |
MinLines |
int |
Minimum number of visible lines. The TextArea will not shrink below this height. Default is 1. |
MaxLines |
int |
Maximum number of visible lines before vertical scrolling begins. 0 for unlimited. Default is 0. |
Events
| Event | Signature | Description |
|---|---|---|
TextChanged |
EventHandler<string> |
Raised whenever Text changes, either by user input or programmatic assignment. The string argument is the new text value. Fires after the internal state is updated. |
FocusChanged |
EventHandler<bool> |
Raised when the field gains or loses keyboard focus. The boolean is the new IsFocused value. |
CursorPositionChanged |
EventHandler<int> |
Raised when the cursor position changes, either by click, arrow keys, or programmatic assignment. |
Code Example
Basic TextBox (Filled Style)
var nameField = new TextBox
{
Text = "",
Placeholder = "Full Name",
FieldStyle = TextFieldStyle.Filled,
MaxLength = 100,
X = 40,
Y = 40,
Width = 300,
Height = 56
};
nameField.Initialize();
nameField.TextChanged += (s, text) =>
Console.WriteLine($"Name updated: {text}");
drawingManager.AddComponent(nameField);
drawingManager.RequestRedraw();
Outlined Password Field with Error
var passwordField = new TextBox
{
Placeholder = "Password",
IsPassword = true,
FieldStyle = TextFieldStyle.Outlined,
MaxLength = 32,
HelperText = "Must be at least 8 characters",
X = 40,
Y = 120,
Width = 300,
Height = 56
};
passwordField.Initialize();
passwordField.TextChanged += (s, text) =>
{
passwordField.HasError = text.Length > 0 && text.Length < 8;
passwordField.HelperText = passwordField.HasError
? "Password is too short"
: "Must be at least 8 characters";
};
drawingManager.AddComponent(passwordField);
Multi-Line TextArea
var descriptionArea = new TextArea
{
Text = "",
Placeholder = "Description",
FieldStyle = TextFieldStyle.Outlined,
WordWrap = true,
MinLines = 3,
MaxLines = 8,
AcceptsReturn = true,
AcceptsTab = false,
X = 40,
Y = 200,
Width = 400,
Height = 120
};
descriptionArea.Initialize();
descriptionArea.TextChanged += (s, text) =>
Console.WriteLine($"Description lines: {descriptionArea.LineCount}");
drawingManager.AddComponent(descriptionArea);
ReadOnly TextBox with Leading Icon
var iconPath = SKPath.ParseSvgPathData(
"M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-2 12H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z");
var readonlyField = new TextBox
{
Text = "This field is not editable",
IsReadOnly = true,
LeadingIcon = iconPath,
FieldStyle = TextFieldStyle.Filled,
X = 40,
Y = 350,
Width = 400,
Height = 56
};
readonlyField.Initialize();
drawingManager.AddComponent(readonlyField);
drawingManager.RequestRedraw();
Tip
Text input in SkiaSharp-rendered controls relies on keyboard event forwarding. The TextBox control registers itself with the InputManager on focus to receive OnKeyDown and OnKeyPress events. Ensure your host application forwards platform keyboard events to the InputManager for text input to work.