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.
className with classNameFieldOverrides() for consistent Tailwind editingchildrenAsTextareaFieldOverrides() for simple text (span, p, headings)childrenFieldOverrides() for nested components (div, containers)childrenAsTipTapFieldOverrides() for rich text (Markdown components)textInputFieldOverrides() for the best UXcommonFieldOverrides() when you need standard className/children handlingThese advanced configuration techniques work seamlessly with:
With advanced configuration mastered, explore:
These advanced techniques transform UI Builder from a simple visual editor into a powerful, domain-specific design tool tailored to your exact needs.
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.
classNameFieldOverrides(layer)Advanced Tailwind CSS class editor with:
tsx1fieldOverrides: { 2 className: (layer) => classNameFieldOverrides(layer) 3}
childrenFieldOverrides(layer)Searchable component selector for child components:
tsx1fieldOverrides: { 2 children: (layer) => childrenFieldOverrides(layer) 3}
childrenAsTextareaFieldOverrides(layer)Multi-line text editor for simple text content:
tsx1fieldOverrides: { 2 children: (layer) => childrenAsTextareaFieldOverrides(layer) 3}
childrenAsTipTapFieldOverrides(layer)Rich text editor using TipTap:
tsx1fieldOverrides: { 2 children: (layer) => childrenAsTipTapFieldOverrides(layer) 3}
iconNameFieldOverrides(layer)Visual icon picker:
tsx1fieldOverrides: { 2 iconName: (layer) => iconNameFieldOverrides(layer) 3}
textInputFieldOverrides(layer, allowVariableBinding, propName)Enhanced text input with optional variable binding support:
allowVariableBinding is truetsx1fieldOverrides: { 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// }
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}
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});
Provide sensible default child components when users add your component to the canvas.
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}
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.
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}
Automatically bind component properties to variables when components are added to the canvas. Perfect for system data, branding, and user information.
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}
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:
When using textInputFieldOverrides with variable binding enabled, users see:
See these advanced configuration techniques in action: