App Builder Components | Inputs

Learn about the specific components you can use in the app builder here

Text Input

The Text Input component is the standard single-line form field used for capturing strings, numbers, or simple text data. It is deeply integrated with the App Builder's state management system, allowing for dynamic default values and real-time data binding.

Key Features

  • Dynamic Data Seeding: Supports initial values derived from system context (e.g., {{system.user.email}}) or URL parameters.
  • State Binding: Automatically syncs user input to the global pageData object using the configured field_key.
  • Validation: Supports required fields and custom error states.
  • Hidden Mode: Can be set to hidden to pass context or default values to a form submission without user interaction. In the App Builder, hidden inputs remain visible as placeholders for easier editing.

Configuration Props

PropTypeDescription
field_keystringRequired. The unique key in pageData where this input's value will be stored (e.g., user.first_name).
inputValuestringThe default value configuration. Supports static text or dynamic expressions like {{system.date.today}}.
labelstringThe visual label displayed above the input.
placeholderstringGhost text shown when the input is empty.
is_requiredbooleanIf true, adds an asterisk to the label and enforces validation.
hiddenbooleanIf true, the input is not rendered in the runtime UI but still registers its value in state.

Technical Behavior (Seeding Strategy A)

This component uses Seeding Strategy A. When the component mounts:

  1. It checks if pageData[field_key] is currently undefined or null.
  2. If empty, it resolves the inputValue expression (e.g., {{params.id}} -> 123).
  3. It sets this resolved value into the pageData atom.
  4. Note: User edits are preserved; the default value only applies if the field is empty on mount.

Rich Text Input

The Rich Text Input component provides a full WYSIWYG (What You See Is What You Get) editing experience using Markdown. It is ideal for long-form content, descriptions, or notes where formatting (bold, lists, headers) is required.

Key Features

  • Markdown Native: Data is stored and retrieved as Markdown strings, making it portable and easy to render elsewhere.
  • Prose Styling: Wraps content in a Tailwind prose container for beautiful typography out of the box.
  • Context Aware Defaults: Like the standard Text Input, it supports dynamic default values (e.g., pre-filling a standard email template).

Configuration Props

PropTypeDescription
field_keystringRequired. The key in pageData to store the markdown string.
inputValuestringInitial markdown content. Can include dynamic variables (e.g., # Report for {{record.id}}).
labelstringLabel displayed above the editor area.
editor_container_class_namestringCSS classes to control the editor's height, border, and background.

Technical Behavior

  • State Handling: It handles both raw string values and legacy markdown objects ({ markdown: "..." }) gracefully, ensuring backward compatibility.
  • Builder Experience: In App Builder mode, the editor functions normally, but interactions are wrapped to prevent conflict with the drag-and-drop system.
  • Performance: Utilizes MdxEditor for a lightweight editing experience that doesn't bloat the bundle size.

Upload File

The Upload File component serves a dual purpose: it can act as a standalone utility for immediate file uploads (with redirection) or as a form input that attaches uploaded file records to the current page's data context. It handles file selection, drag-and-drop, video compression options, and API communication seamlessly.

Key Features

  • Dual Mode Operation:

  • Utility Mode: Uploads files immediately and redirects the user to a file view page (default behavior when no field_key is set).

  • Input Mode: Uploads files and stores the resulting file records (IDs, URLs, metadata) into the pageData state, allowing them to be submitted as part of a larger form.

  • Video Compression: Automatically detects video files and offers selectable compression profiles (e.g., "Standard", "High Quality 720p", "MMS/Email").

  • Drag & Drop: Native support for dragging files directly onto the component area.

  • Privacy Controls: Toggle between "Public" and "Private" upload visibility before the upload begins.

Configuration Props

PropTypeDescription
field_keystringOptional. If set, switches the component to Input Mode. The uploaded file records (array) will be saved to this key in pageData (e.g., uploaded_files). If omitted, the component defaults to Utility Mode (redirects after upload).
onUploadCompletefunctionCustom callback function triggered after a successful upload. Receives the array of uploaded file objects.
default_to_publicbooleanSets the initial state of the "Public File" toggle. Default is false (Private).
ask_if_publicbooleanIf true, shows the toggle allowing users to choose between Public/Private. If false, the toggle is hidden and uses the default.
attach_onlybooleanFuture feature: Restricts uploads to specific file types or attachment modes.
class_namestringCSS classes for the outer container. Defaults to a dashed border style.

Technical Behavior

  • API Integration: Uses the useApiHook to POST FormData to the v1/files endpoint.
  • State Integration (Input Mode): When field_key is present, successful uploads trigger an Immer producer that appends the new file records to the existing array at pageData[field_key]. It does not overwrite existing data, allowing users to upload multiple batches of files into the same field.
  • Navigation Guard: In Input Mode, the automatic navigation (Maps(...)) is suppressed to ensure the user remains on the form to complete their submission.
  • Mime-Type Detection: The component inspects file types on selection (e.g., file.type.startsWith('video/')) to dynamically reveal compression options only when relevant.

Button / Action Trigger

The Button component is the primary mechanism for triggering logic and data operations within an application. While it visually appears simple, it houses a powerful execution engine capable of interacting with system APIs, triggering automations, and handling complex data payloads dynamically.

Key Features

  • API Discovery: Integrated directly with the system's OpenAPI specification. Builders can select endpoints from a searchable dropdown (GET /v1/users) rather than manually typing URL paths.
  • Smart Context Injection: Supports full access to the Data Taxonomy. You can inject {{pageData}} values into a JSON request body or use {{record.id}} in a URL path parameter.
  • JSON Type Safety: The request body editor uses a specialized parsing mode (jsonSafe: true). This ensures that dynamic variables resolve correctly within a JSON structure (e.g., resolving undefined variables to null instead of empty strings to prevent syntax errors).
  • Visual Feedback: Automatically handles loading states (disabling the button and showing a spinner) and displays success/error toast notifications based on the API response.

Configuration Props

PropTypeDescription
textstringThe visible label text on the button (e.g., "Submit", "Delete").
action_typestringDetermines the execution logic. Currently supports "Valstorm API Request" (triggers system endpoints). Future support planned for "Automation" and "External API".
valstorm_api_configobjectA configuration object containing the selected method, path, dynamic params map, and the JSON body template.
class_namestringCSS classes for styling the button (colors, padding, rounded corners).

Technical Behavior

  • Path Resolution: The component parses the selected API path (e.g., /users/{id}). It looks for dynamic parameters defined in the settings. If a parameter matches a path segment (like {id}), it replaces it. If it does not match a path segment, it is automatically appended as a Query Parameter (e.g., ?search=...).

  • Body Parsing: Before the request is sent, the body string is processed by the Expression Parser.

  • Variables resolving to Objects/Arrays are JSON.stringify'd automatically.

  • Variables resolving to undefined become null.

  • The result is then parsed back into a valid JSON object to be sent over the network.

  • Builder Mode: In the App Builder, clicking the button selects the component for editing rather than executing the API call, preventing accidental data mutations while designing.

Phone Input

The Phone Input component is a specialized form field designed to capture structured phone number data. Unlike a standard text input, it manages three distinct pieces of data—Country Code, Friendly Number (for display), and Extension—and combines them into a single unified object for storage.

Key Features

  • Structured Data: Automatically splits the input into country_code, friendly_number, and extension.
  • Auto-Formatting: As the user types, the "Friendly Number" field automatically applies US formatting (555) 123-4567 for better readability.
  • Data Normalization: Behind the scenes, it constructs a clean phone_number string (e.g., +15551234567) optimized for backend storage and searching.
  • Smart Defaults: Defaults to +1 (US) country code but allows overrides.

Configuration Props

PropTypeDescription
field_keystringRequired. The key in pageData where the phone object will be stored.
inputValuestringThe default value (e.g., +18005551234). The component parses string defaults into the structured object automatically on mount.
labelstringThe label displayed above the input group.
is_requiredbooleanIf true, adds an asterisk to the label. Note: Validation typically checks if the main number is populated.
hiddenbooleanIf true, hides the input group but preserves the data in state.

Technical Behavior

This component uses a composite state object. When you bind this input to a key like contact.phone, the data stored in pageData is not a string, but an object:

{ "country_code": "+1", "friendly_number": "(555) 123-4567", "extension": "101", "phone_number": "+15551234567" }
  • Seeding: If the field is empty on mount, it hydrates state using the inputValue. If inputValue is a simple string (e.g., +15551234567), the component attempts to parse and format it into the object structure automatically.
  • Immer Integration: Updates are handled via immer's produce, ensuring that typing in the "Extension" field updates that specific property without overwriting the main number or country code.