Skip to main content

TextInput Component

The TextInput component is a versatile input field for capturing and displaying text from users. It supports various input types, validation, and rich event handling.

Overview

TextInput provides a complete text input solution with:

  • Multiple input types (text, email, password, number, etc.)
  • Built-in validation
  • Copy/clear functionality
  • Character counting
  • Placeholder and helper text
  • Disabled and readonly states
  • Comprehensive event system

Basic Usage

{
uuid: "my-text-input",
name: "username_input",
component_type: ComponentType.TextInput,
input: {
value: { type: "string", value: "default text" },
placeholder: { type: "string", value: "Enter username" },
label: { type: "string", value: "Username" }
},
event: {
onChange: `
console.log('Input value:', EventData.value);
`
}
}

Component Properties

PropertyTypeDescription
valuestringCurrent input value
placeholderstringPlaceholder text when empty
labelstringLabel text displayed above input
typestringInput type (text, email, password, etc.)
sizestringInput size: 'small', 'medium', 'large'
disabledbooleanDisable input interaction
readonlybooleanMake input read-only
requiredbooleanMark as required

Input Handlers Reference

Input handlers in TextInput allow dynamic evaluation of properties. They are evaluated in real-time and update the component accordingly.

Handler Evaluation Flow

value

Type: string | handler

The current value of the input field.

Dynamic Example:

input: {
value: {
type: "handler",
value: `
// Load user's saved preference
const user = Vars.currentUser;
return user?.preferences?.textInput?.lastValue || "";
`
}
}

Static Example:

input: {
value: { type: "string", value: "Initial text" }
}

placeholder

Type: string | handler

Placeholder text displayed when input is empty.

Dynamic Example:

input: {
placeholder: {
type: "handler",
value: `
return Vars.appSettings?.placeholders?.textInput || "Enter text...";
`
}
}

label

Type: string | handler

Label text displayed above the input.

Dynamic Example:

input: {
label: {
type: "handler",
value: `
return Vars.isRequired ? "Username *" : "Username";
`
}
}

type

Type: string

Input type attribute. Common values: text, email, password, number, tel, url.

input: {
type: { type: "string", value: "email" }
}

size

Type: string

Input size: small, medium, large.

input: {
size: { type: "string", value: "medium" }
}

disabled

Type: boolean | handler

Whether input is disabled.

Dynamic Example:

input: {
disabled: {
type: "handler",
value: `
return Vars.isProcessing || Vars.formSubmitted;
`
}
}

readonly

Type: boolean

Make input read-only (can select but not edit).

input: {
readonly: { type: "boolean", value: false }
}

required

Type: boolean

Mark field as required for validation.

input: {
required: { type: "boolean", value: true }
}

helper

Type: string | handler

Helper text displayed below input.

Dynamic Example:

input: {
helper: {
type: "handler",
value: `
if (Vars.showValidation && !Vars.emailValid) {
return "Please enter a valid email address";
}
return "We'll never share your email";
`
}
}

maxLength

Type: number

Maximum character length.

input: {
maxLength: { type: "number", value: 100 }
}

showCount

Type: boolean

Display character count when maxLength is set.

input: {
showCount: { type: "boolean", value: true },
maxLength: { type: "number", value: 100 }
}

allowClear

Type: boolean

Show clear button to quickly empty the field.

input: {
allowClear: { type: "boolean", value: true }
}

withCopy

Type: boolean

Show copy button to copy value to clipboard.

input: {
withCopy: { type: "boolean", value: true }
}

Validation Handlers

Type: boolean

Control when validation occurs.

input: {
validateOnChange: { type: "boolean", value: true },
validateOnBlur: { type: "boolean", value: true },
hasFeedback: { type: "boolean", value: true }
}

rules

Type: array

Validation rules.

input: {
rules: {
type: "array",
value: [
{ required: true, message: "Username is required" },
{ min: 3, message: "Minimum 3 characters" },
{ pattern: /^[a-zA-Z0-9_]+$/, message: "Only alphanumeric and underscore allowed" }
]
}
}

min / max / step

Type: number

For number type inputs.

input: {
type: { type: "string", value: "number" },
min: { type: "number", value: 0 },
max: { type: "number", value: 100 },
step: { type: "number", value: 5 }
}

autocomplete

Type: string

HTML autocomplete attribute value.

input: {
autocomplete: { type: "string", value: "email" }
}

Handler Execution Context

When a handler is evaluated, you have access to:

// Access variables
Vars.username = "John"

// Access current component
Current.name // Component name
Current.uuid // Component ID
Current.Instance // Component runtime values

// Access microapp context (if in microapp)
// Local scope (default)
Vars.localVar = value

// Global scope (shared)
Vars['global.theme'] = 'dark'

Microapp Input Handler Isolation

In microapps, input handler evaluation is scoped:

  • Local variables are isolated to the microapp instance
  • Global variables are shared across all instances
  • Handlers have access to the microapp's isolated runtime only

Events Reference

Events in TextInput allow you to respond to user interactions. Each event receives EventData containing relevant information about the interaction.

Event Execution Flow

onChange

Triggered: When input value changes

EventData:

{
value: string // New value
oldValue: string // Previous value
event: Event // Native event
}

Example:

event: {
onChange: `
Vars.username = EventData.value;

// Validate
if (EventData.value.length < 3) {
Vars.usernameError = "Minimum 3 characters";
} else {
Vars.usernameError = "";
}
`
}

onFocus

Triggered: When input receives focus

EventData:

{
value: string // Current value
event: Event // Native event
}

Example:

event: {
onFocus: `
Vars.activeField = "username";
Vars.helpTextVisible = true;
`
}

onBlur

Triggered: When input loses focus

EventData:

{
value: string // Final value
event: Event // Native event
}

Example:

event: {
onBlur: `
Vars.activeField = null;

// Perform final validation
const isValid = EventData.value.length >= 3;
Vars.showValidation = true;
Vars.usernameValid = isValid;
`
}

onEnter

Triggered: When Enter key is pressed

EventData:

{
value: string // Current value
event: Event // Keyboard event
}

Example:

event: {
onEnter: `
// Submit form on Enter
if (Vars.usernameValid) {
SubmitForm();
}
`
}

onClear

Triggered: When clear button is clicked (if allowClear is true)

EventData:

{
value: string // Should be empty
event: Event // Click event
}

Example:

event: {
onClear: `
Vars.username = "";
Vars.usernameError = "";
Vars.showValidation = false;
`
}

onArrowUp / onArrowDown

Triggered: When arrow keys are pressed (useful for number inputs or autocomplete)

EventData:

{
event: KeyboardEvent // Keyboard event
}

Example:

event: {
onArrowUp: `
if (Current.input?.type?.value === "number") {
const current = parseInt(EventData.event.target.value) || 0;
EventData.event.target.value = current + 1;
}
`
}

Common Event Patterns

Form Submission Handler

event: {
onEnter: `
const email = EventData.value;

// Validate
const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
if (!isValid) {
Vars.error = "Invalid email";
return;
}

// Submit
const result = await SubmitEmail(email);
Vars.success = result.success;
`
}
event: {
onChange: `
const query = EventData.value;
Vars.searchQuery = query;

if (query.length >= 2) {
const results = await SearchAPI(query);
Vars.searchResults = results;
} else {
Vars.searchResults = [];
}
`
}

Dependent Field Updates

event: {
onChange: `
const country = EventData.value;
Vars.selectedCountry = country;

// Update related field
const cities = Vars.citiesByCountry[country] || [];
Vars.availableCities = cities;
Vars.selectedCity = ""; // Reset city selection
`
}

Character Limit Enforcement

event: {
onChange: `
const maxChars = 100;
let value = EventData.value;

if (value.length > maxChars) {
value = value.substring(0, maxChars);
Current.Instance.value = value; // Update component
}

Vars.charCount = value.length;
Vars.charsRemaining = maxChars - value.length;
`
}

EventData Structure Reference

All TextInput events provide EventData object:

EventData = {
value?: string // New/current value
oldValue?: string // Previous value (onChange only)
event?: Event | KeyboardEvent // Native browser event
}

Microapp Event Isolation

Events in microapps maintain isolation:

// Local scope (microapp instance only)
Vars.username = EventData.value

// Global scope (shared across instances)
Vars['global.lastActivity'] = Date.now()

// Component-scoped state
Current.Instance.validationState = "pending"

When an event handler accesses Vars, it operates in the microapp's local scope by default. To access global variables, use the global. prefix.

Async Event Handling

Event handlers support async operations:

event: {
onChange: `
const value = EventData.value;

// Start validation
Vars.validating = true;

try {
const result = await ValidateUsername(value);
Vars.isAvailable = result.available;
Vars.validationError = result.error || "";
} catch (err) {
Vars.validationError = "Validation failed";
} finally {
Vars.validating = false;
}
`
}

Styling

TextInput supports dynamic styling through styleHandlers:

{
styleHandlers: {
width: `return Vars.isCompact ? '200px' : '100%';`,
backgroundColor: `return Vars.theme === 'dark' ? '#333' : '#fff';`
}
}

Complete Example

Here's a complete TextInput example combining inputs, events, and styling:

{
uuid: "email-input",
name: "email_field",
component_type: ComponentType.TextInput,

// Input handlers for dynamic properties
input: {
value: {
type: "handler",
value: `return Vars.email || "";`
},
label: {
type: "handler",
value: `return Vars.showValidation && !Vars.emailValid ? "Email *" : "Email";`
},
placeholder: {
type: "string",
value: "Enter your email"
},
type: { type: "string", value: "email" },
required: { type: "boolean", value: true },
helper: {
type: "handler",
value: `
if (Vars.showValidation && !Vars.emailValid) {
return "Please enter a valid email address";
}
return "We'll never share your email";
`
},
disabled: {
type: "handler",
value: `return Vars.isSubmitting;`
}
},

// Event handlers for user interactions
event: {
onChange: `
Vars.email = EventData.value;

// Real-time validation
const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(EventData.value);
Vars.emailValid = isValid;
`,

onBlur: `
Vars.showValidation = true;
`,

onEnter: `
if (Vars.emailValid) {
SubmitForm();
}
`
},

// Dynamic styling
styleHandlers: {
width: `return Vars.isCompact ? '200px' : '100%';`,
borderColor: `
if (Vars.showValidation && !Vars.emailValid) {
return '#ff0000';
}
return '#ccc';
`,
opacity: `return Vars.isSubmitting ? '0.6' : '1';`
}
}

Microapp Integration

TextInput components in microapps maintain isolated state:

// Local variable (microapp-scoped)
Vars.username = 'John'

// Global variable (shared across all instances)
Vars['global.theme'] = 'dark'

See Variable Scopes for details on local vs global scope in microapps.


Source Code Reference

  • Component: src/shared/ui/components/inputs/TextInput/TextInput.ts
  • Base Class: src/shared/ui/components/base/BaseElement.ts
  • Runtime: src/features/runtime/state/runtime-context.ts | disabled | boolean | Disable input interaction | | readonly | boolean | Make input read-only | | required | boolean | Mark as required |

Input Handlers & Events

Available Input Handlers

See TextInput Input Handlers for complete reference including:

  • value - Dynamic value evaluation
  • placeholder - Dynamic placeholder
  • label - Dynamic label
  • disabled - Dynamic disabled state
  • And more...

Available Events

See TextInput Events for complete reference including:

  • onChange - Triggered on value change
  • onFocus - Triggered on focus
  • onBlur - Triggered on blur
  • onEnter - Triggered when Enter key pressed
  • onClear - Triggered when clear button clicked
  • And more...

Common Examples

Display User Input

{
input: {
value: {
type: "handler",
value: `return Vars.username || '';`
}
}
}

Handle Text Changes

event: {
onChange: `
Vars.username = EventData.value;
Vars.formDirty = true;
`
}

Validate Email Input

{
input: {
type: { type: "string", value: "email" },
rules: {
type: "array",
value: [{ required: true, message: "Email is required" }]
}
},
event: {
onChange: `
const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(EventData.value);
Vars.emailValid = isValid;
`
}
}

Styling

TextInput supports dynamic styling through styleHandlers:

{
styleHandlers: {
width: `return Vars.isCompact ? '200px' : '100%';`,
backgroundColor: `return Vars.theme === 'dark' ? '#333' : '#fff';`
}
}

Microapp Integration

TextInput components in microapps maintain isolated state:

// Local variable (microapp-scoped)
Vars.username = 'John'

// Global variable (shared across all instances)
Vars['global.theme'] = 'dark'

Events in microapps are scoped to the instance. See Variable Scopes for details.

See Also