Take your component integration to the next level with field overrides, default children, and automatic variable bindings. These advanced techniques create polished, user-friendly editing experiences.
Field Overrides
Field overrides replace auto-generated form fields with specialized input controls. Instead of basic text inputs, users get rich editors, color pickers, icon selectors, and more.
Available Built-in Field Overrides
classNameFieldOverrides(layer)
Advanced Tailwind CSS class editor with:
- Auto-complete for Tailwind classes
- Responsive breakpoint controls (sm:, md:, lg:, xl:)
- Visual class grouping and validation
- Theme-aware suggestions
tsx1fieldOverrides: { 2 className: (layer) => classNameFieldOverrides(layer) 3}
childrenFieldOverrides(layer)
Searchable component selector for child components:
- Dropdown with available component types
- Search and filter capabilities
- Respects component hierarchy
tsx1fieldOverrides: { 2 children: (layer) => childrenFieldOverrides(layer) 3}
childrenAsTextareaFieldOverrides(layer)
Multi-line text editor for simple text content:
- Perfect for span, p, and heading elements
- Multi-line editing support
tsx1fieldOverrides: { 2 children: (layer) => childrenAsTextareaFieldOverrides(layer) 3}
childrenAsTipTapFieldOverrides(layer)
Rich text editor using TipTap:
- WYSIWYG markdown editing
- Formatting toolbar with bold, italic, links
- Ideal for Markdown components
tsx1fieldOverrides: { 2 children: (layer) => childrenAsTipTapFieldOverrides(layer) 3}
iconNameFieldOverrides(layer)
Visual icon picker:
- Grid of available icons
- Search functionality
- Live preview
tsx1fieldOverrides: { 2 iconName: (layer) => iconNameFieldOverrides(layer) 3}
textInputFieldOverrides(layer, allowVariableBinding, propName)
Enhanced text input with optional variable binding support:
- Variable binding UI when
allowVariableBinding
is true - Automatic binding/unbinding controls
- Immutable binding badges
tsx1fieldOverrides: { 2 title: (layer) => textInputFieldOverrides(layer, true, 'title') 3}
commonFieldOverrides()
Convenience function that applies standard overrides for className
and children
:
tsx1fieldOverrides: commonFieldOverrides() 2// Equivalent to: 3// { 4// className: (layer) => classNameFieldOverrides(layer), 5// children: (layer) => childrenFieldOverrides(layer) 6// }
Creating Custom Field Overrides
Create specialized input controls for unique data types:
tsx1import { AutoFormInputComponentProps } from '@/components/ui/ui-builder/types'; 2import { FormItem, FormLabel, FormControl } from '@/components/ui/form'; 3 4const colorPickerFieldOverride = (layer) => ({ 5 fieldType: ({ label, field }: AutoFormInputComponentProps) => ( 6 <FormItem> 7 <FormLabel>{label}</FormLabel> 8 <FormControl> 9 <div className="flex gap-2 items-center"> 10 <input 11 type="color" 12 value={field.value || '#000000'} 13 onChange={(e) => field.onChange(e.target.value)} 14 className="w-12 h-8 rounded border cursor-pointer" 15 /> 16 <input 17 type="text" 18 value={field.value || ''} 19 onChange={(e) => field.onChange(e.target.value)} 20 placeholder="#000000" 21 className="flex-1 px-3 py-2 border rounded-md" 22 /> 23 </div> 24 </FormControl> 25 </FormItem> 26 ) 27}); 28 29// Use in component definition: 30fieldOverrides: { 31 brandColor: colorPickerFieldOverride, 32 className: (layer) => classNameFieldOverrides(layer) 33}
Conditional Field Overrides
Hide or show fields based on other prop values:
tsx1const conditionalFieldOverride = (layer) => ({ 2 isHidden: (currentValues) => currentValues.mode === 'simple', 3 fieldType: ({ label, field }) => ( 4 <FormItem> 5 <FormLabel>{label}</FormLabel> 6 <FormControl> 7 <AdvancedEditor value={field.value} onChange={field.onChange} /> 8 </FormControl> 9 </FormItem> 10 ) 11});
Default Children
Provide sensible default child components when users add your component to the canvas.
Simple Text Defaults
For basic text components:
tsx1span: { 2 schema: z.object({ 3 className: z.string().optional(), 4 children: z.string().optional(), 5 }), 6 fieldOverrides: { 7 className: (layer) => classNameFieldOverrides(layer), 8 children: (layer) => childrenAsTextareaFieldOverrides(layer) 9 }, 10 defaultChildren: "Default text content" 11}
Component Layer Defaults
For complex nested structures:
tsx1Button: { 2 component: Button, 3 schema: z.object({ 4 className: z.string().optional(), 5 children: z.any().optional(), 6 variant: z.enum(['default', 'destructive']).default('default'), 7 }), 8 from: '@/components/ui/button', 9 defaultChildren: [ 10 { 11 id: "button-text", 12 type: "span", 13 name: "Button Text", 14 props: {}, 15 children: "Click me", 16 } 17 ], 18 fieldOverrides: commonFieldOverrides() 19}
Important: All component types referenced in defaultChildren
must exist in your registry.
Rich Default Structures
Create sophisticated default layouts:
tsx1Card: { 2 component: Card, 3 schema: z.object({ 4 className: z.string().optional(), 5 children: z.any().optional(), 6 }), 7 from: '@/components/ui/card', 8 defaultChildren: [ 9 { 10 id: "card-header", 11 type: "div", 12 name: "Header", 13 props: { className: "p-6 pb-0" }, 14 children: [ 15 { 16 id: "card-title", 17 type: "span", 18 name: "Title", 19 props: { className: "text-2xl font-semibold" }, 20 children: "Card Title" 21 } 22 ] 23 }, 24 { 25 id: "card-content", 26 type: "div", 27 name: "Content", 28 props: { className: "p-6" }, 29 children: "Card content goes here." 30 } 31 ], 32 fieldOverrides: commonFieldOverrides() 33}
Default Variable Bindings
Automatically bind component properties to variables when components are added to the canvas. Perfect for system data, branding, and user information.
Basic Variable Bindings
tsx1UserProfile: { 2 component: UserProfile, 3 schema: z.object({ 4 userId: z.string().default(''), 5 displayName: z.string().default('Anonymous'), 6 email: z.string().optional(), 7 }), 8 from: '@/components/ui/user-profile', 9 defaultVariableBindings: [ 10 { 11 propName: 'userId', 12 variableId: 'current_user_id', 13 immutable: true // System data - cannot be unbound 14 }, 15 { 16 propName: 'displayName', 17 variableId: 'current_user_name', 18 immutable: false // Can be customized 19 } 20 ], 21 fieldOverrides: { 22 userId: (layer) => textInputFieldOverrides(layer, true, 'userId'), 23 displayName: (layer) => textInputFieldOverrides(layer, true, 'displayName'), 24 email: (layer) => textInputFieldOverrides(layer, true, 'email'), 25 } 26}
Immutable Bindings for Critical Data
Use immutable: true
to prevent users from unbinding critical data:
tsx1BrandedButton: { 2 component: BrandedButton, 3 schema: z.object({ 4 text: z.string().default('Click me'), 5 brandColor: z.string().default('#000000'), 6 companyName: z.string().default('Company'), 7 }), 8 from: '@/components/ui/branded-button', 9 defaultVariableBindings: [ 10 { 11 propName: 'brandColor', 12 variableId: 'primary_brand_color', 13 immutable: true // Prevents breaking brand guidelines 14 }, 15 { 16 propName: 'companyName', 17 variableId: 'company_name', 18 immutable: true // Consistent branding 19 } 20 // 'text' is not bound, allowing content customization 21 ], 22 fieldOverrides: { 23 text: (layer) => textInputFieldOverrides(layer, true, 'text'), 24 brandColor: (layer) => textInputFieldOverrides(layer, true, 'brandColor'), 25 companyName: (layer) => textInputFieldOverrides(layer, true, 'companyName'), 26 } 27}
When to Use Immutable Bindings:
- System data: User IDs, tenant IDs, system versions
- Brand consistency: Colors, logos, company names
- Security: Roles, permissions, access levels
- Template integrity: Critical variables in white-label scenarios
Variable Binding UI
When using textInputFieldOverrides
with variable binding enabled, users see:
- ๐ Bind Variable button for unbound properties
- Variable name, type, and default value for bound properties
- ๐ Immutable badge for protected bindings
- Unbind button for mutable bindings only
Live Example
See these advanced configuration techniques in action:
Best Practices
Field Overrides
- Always override
className
withclassNameFieldOverrides()
for consistent Tailwind editing - Choose appropriate children overrides based on content type:
childrenAsTextareaFieldOverrides()
for simple text (span, p, headings)childrenFieldOverrides()
for nested components (div, containers)childrenAsTipTapFieldOverrides()
for rich text (Markdown components)
- Create domain-specific overrides for complex data types (colors, dates, files)
- Use conditional overrides to hide advanced options in simple mode
Default Children
- Provide meaningful defaults that demonstrate proper component usage
- Keep structures shallow initially to avoid overwhelming new users
- Use descriptive names for child layers to help with navigation
- Include all dependencies - ensure referenced component types are in your registry
- Use unique IDs to prevent conflicts when components are duplicated
Variable Bindings
- Use immutable bindings for:
- System data (user IDs, system versions)
- Brand elements (colors, logos, company names)
- Security-sensitive data (roles, permissions)
- Template integrity variables
- Leave content variables mutable so editors can customize text and messaging
- Combine with field overrides using
textInputFieldOverrides()
for the best UX - Test binding scenarios to ensure the editing experience is smooth
Performance Tips
- Use
commonFieldOverrides()
when you need standard className/children handling - Memoize expensive overrides if they perform complex calculations
- Keep default children reasonable to avoid slow initial renders
- Cache field override functions to prevent unnecessary re-renders
Integration with Other Features
These advanced configuration techniques work seamlessly with:
- Variables Panel - Manage variables that power your bindings
- Props Panel - Enhanced forms with your custom field overrides
- Code Generation - Exported code respects your component definitions
- LayerRenderer - Variable values are resolved at render time
What's Next?
With advanced configuration mastered, explore:
- Variables - Create dynamic, data-driven interfaces
- Panel Configuration - Customize the editor panels themselves
- Persistence - Save and load your enhanced component configurations
These advanced techniques transform UI Builder from a simple visual editor into a powerful, domain-specific design tool tailored to your exact needs.