Variables are the key to creating dynamic, data-driven interfaces with UI Builder. Instead of hardcoding static values into your components, variables allow you to bind component properties to dynamic data that can change at runtime.
This transforms static designs into powerful applications with:
UI Builder supports four typed variables:
| Type | Use Case | Default Value |
|---|---|---|
string | Text content, names, URLs, colors | Any string |
number | Counts, ages, prices, quantities | Any number |
boolean | Feature flags, visibility toggles, active states | true or false |
function | Event handlers (onClick, onSubmit, onChange) | Function registry key |
tsx1interface Variable { 2 id: string; // Unique identifier 3 name: string; // Display name (becomes property name in generated code) 4 type: 'string' | 'number' | 'boolean' | 'function'; 5 defaultValue: string | number | boolean; // Must match the type 6} 7 8// Examples: 9const stringVar: Variable = { 10 id: 'page-title', 11 name: 'pageTitle', 12 type: 'string', 13 defaultValue: 'Welcome to UI Builder' 14}; 15 16const numberVar: Variable = { 17 id: 'user-age', 18 name: 'userAge', 19 type: 'number', 20 defaultValue: 25 21}; 22 23const booleanVar: Variable = { 24 id: 'is-loading', 25 name: 'isLoading', 26 type: 'boolean', 27 defaultValue: false 28}; 29 30// Function variables reference a key in your FunctionRegistry 31const functionVar: Variable = { 32 id: 'submit-handler', 33 name: 'handleSubmit', 34 type: 'function', 35 defaultValue: 'handleFormSubmit' // Key in functionRegistry 36};
Function variables enable binding event handlers like onClick, onSubmit, and onChange to pre-defined functions. Unlike data variables, function variables reference a key in your FunctionRegistry.
To use function variables:
functionRegistry to UIBuilder with your available functionsonClick on buttons or onSubmit on formsSee Function Registry for complete documentation on creating functions, binding them to components, and handling form submissions, toasts, and analytics.
š” See it in action: The demo above shows string, number, and boolean types with real-time variable binding.
Set up variables when initializing the UIBuilder:
tsx1import UIBuilder from '@/components/ui/ui-builder'; 2import { Variable } from '@/components/ui/ui-builder/types'; 3 4const initialVariables: Variable[] = [ 5 { 6 id: 'welcome-msg', 7 name: 'welcomeMessage', 8 type: 'string', 9 defaultValue: 'Welcome to our site!' 10 }, 11 { 12 id: 'user-count', 13 name: 'userCount', 14 type: 'number', 15 defaultValue: 0 16 }, 17 { 18 id: 'show-banner', 19 name: 'showBanner', 20 type: 'boolean', 21 defaultValue: true 22 } 23]; 24 25function App() { 26 return ( 27 <UIBuilder 28 componentRegistry={myComponentRegistry} 29 initialVariables={initialVariables} 30 onVariablesChange={(variables) => { 31 // Persist variable definitions to your backend 32 console.log('Variables updated:', variables); 33 }} 34 /> 35 ); 36}
Users can create variables directly in the editor:
Variables can be bound to component properties in two ways:
Users can bind variables to component properties in the props panel by clicking the link icon next to any field.
Components can be configured to automatically bind to specific variables when added:
tsx1const componentRegistry = { 2 UserProfile: { 3 component: UserProfile, 4 schema: z.object({ 5 userId: z.string(), 6 displayName: z.string(), 7 }), 8 from: '@/components/ui/user-profile', 9 // Automatically bind user data when component is added 10 defaultVariableBindings: [ 11 { 12 propName: 'userId', 13 variableId: 'current-user-id', 14 immutable: true // Cannot be unbound in UI 15 }, 16 { 17 propName: 'displayName', 18 variableId: 'current-user-name', 19 immutable: false // Can be changed by users 20 } 21 ] 22 } 23};
Immutable bindings prevent users from unbinding critical variables for system data, branding consistency, and template integrity.
š” Learn more: See Variable Binding for detailed binding mechanics and Data Binding for connecting to external data sources.
Control whether users can edit variables in the UI:
tsx1<UIBuilder 2 allowVariableEditing={false} // Hides add/edit/delete buttons 3 initialVariables={systemVariables} 4 componentRegistry={myComponentRegistry} 5/>
When allowVariableEditing is false:
Respond to variable definition changes in the editor:
tsx1function App() { 2 const handleVariablesChange = (variables: Variable[]) => { 3 // Persist variable definitions to backend 4 fetch('/api/variables', { 5 method: 'POST', 6 body: JSON.stringify(variables) 7 }); 8 }; 9 10 return ( 11 <UIBuilder 12 componentRegistry={myComponentRegistry} 13 onVariablesChange={handleVariablesChange} 14 /> 15 ); 16}
tsx1// Variables for user-specific content 2const userVariables: Variable[] = [ 3 { id: 'user-name', name: 'userName', type: 'string', defaultValue: 'User' }, 4 { id: 'user-avatar', name: 'userAvatar', type: 'string', defaultValue: '/default-avatar.png' }, 5 { id: 'is-premium', name: 'isPremiumUser', type: 'boolean', defaultValue: false } 6];
tsx1// Variables for conditional features 2const featureFlags: Variable[] = [ 3 { id: 'show-beta-feature', name: 'showBetaFeature', type: 'boolean', defaultValue: false }, 4 { id: 'enable-dark-mode', name: 'enableDarkMode', type: 'boolean', defaultValue: true } 5];
tsx1// Variables for client-specific branding 2const brandingVariables: Variable[] = [ 3 { id: 'company-name', name: 'companyName', type: 'string', defaultValue: 'Acme Corp' }, 4 { id: 'primary-color', name: 'primaryColor', type: 'string', defaultValue: '#3b82f6' }, 5 { id: 'logo-url', name: 'logoUrl', type: 'string', defaultValue: '/default-logo.png' } 6];
userName not u)initialVariablesonChange and onVariablesChange)LayerRenderer with variableValues to inject real data at runtimeThis workflow enables the separation of content structure from actual data, making your UI Builder pages truly dynamic and reusable.
š Next Steps: Learn about Variable Binding for detailed binding mechanics, Data Binding for external data integration, and Rendering Pages for runtime usage.