Layer Structure
Understanding layer structure is fundamental to working with UI Builder. Layers define the hierarchical component tree that powers both the visual editor and the rendering system.
ComponentLayer Interface
Every element in UI Builder is represented as a ComponentLayer
with this structure:
tsx1interface ComponentLayer { 2 id: string; // Unique identifier 3 type: string; // Component type from registry 4 name?: string; // Optional display name for editor 5 props: Record<string, any>; // Component properties 6 children: ComponentLayer[] | string; // Child layers or text content 7}
Core Fields
id
: Required unique identifier for each layertype
: Must match a key in your component registry (e.g., 'Button', 'div', 'Card')name
: Optional display name shown in the layers panelprops
: Object containing all component properties (className, variant, etc.)children
: Either an array of child layers or a string for text content
Basic Layer Examples
Simple Text Layer
tsx1const textLayer: ComponentLayer = { 2 id: 'heading-1', 3 type: 'h1', 4 name: 'Page Title', 5 props: { 6 className: 'text-3xl font-bold text-center' 7 }, 8 children: 'Welcome to My App' 9};
Button with Icon
tsx1const buttonLayer: ComponentLayer = { 2 id: 'cta-button', 3 type: 'Button', 4 name: 'CTA Button', 5 props: { 6 variant: 'default', 7 size: 'lg', 8 className: 'w-full max-w-sm' 9 }, 10 children: [ 11 { 12 id: 'button-text', 13 type: 'span', 14 name: 'Button Text', 15 props: {}, 16 children: 'Get Started' 17 }, 18 { 19 id: 'button-icon', 20 type: 'Icon', 21 name: 'Arrow Icon', 22 props: { 23 iconName: 'ArrowRight', 24 size: 'medium' 25 }, 26 children: [] 27 } 28 ] 29};
Hierarchical Structure
Layers form a tree structure where containers hold other layers:
tsx1const cardLayer: ComponentLayer = { 2 id: 'product-card', 3 type: 'div', 4 name: 'Product Card', 5 props: { 6 className: 'bg-white rounded-lg shadow-md p-6' 7 }, 8 children: [ 9 { 10 id: 'card-header', 11 type: 'div', 12 name: 'Header', 13 props: { className: 'mb-4' }, 14 children: [ 15 { 16 id: 'product-title', 17 type: 'h3', 18 name: 'Product Title', 19 props: { className: 'text-xl font-semibold' }, 20 children: 'Amazing Product' 21 }, 22 { 23 id: 'product-badge', 24 type: 'Badge', 25 name: 'Status Badge', 26 props: { variant: 'secondary' }, 27 children: 'New' 28 } 29 ] 30 }, 31 { 32 id: 'card-content', 33 type: 'div', 34 name: 'Content', 35 props: { className: 'space-y-3' }, 36 children: [ 37 { 38 id: 'description', 39 type: 'p', 40 name: 'Description', 41 props: { className: 'text-gray-600' }, 42 children: 'This product will change your life.' 43 }, 44 { 45 id: 'price', 46 type: 'div', 47 name: 'Price Container', 48 props: { className: 'flex items-center justify-between' }, 49 children: [ 50 { 51 id: 'price-text', 52 type: 'span', 53 name: 'Price', 54 props: { className: 'text-2xl font-bold text-green-600' }, 55 children: '$99.99' 56 }, 57 { 58 id: 'buy-button', 59 type: 'Button', 60 name: 'Buy Button', 61 props: { variant: 'default', size: 'sm' }, 62 children: 'Add to Cart' 63 } 64 ] 65 } 66 ] 67 } 68 ] 69};
Layer Types
Container Layers
Layers that hold and organize other layers:
tsx1// Flex container 2{ 3 id: 'nav-container', 4 type: 'div', 5 name: 'Navigation', 6 props: { 7 className: 'flex items-center justify-between p-4' 8 }, 9 children: [/* nav items */] 10} 11 12// Grid container 13{ 14 id: 'grid-layout', 15 type: 'div', 16 name: 'Image Grid', 17 props: { 18 className: 'grid grid-cols-1 md:grid-cols-3 gap-6' 19 }, 20 children: [/* grid items */] 21}
Content Layers
Layers that display content:
tsx1// Text content 2{ 3 id: 'paragraph-1', 4 type: 'p', 5 name: 'Description', 6 props: { 7 className: 'text-base leading-relaxed' 8 }, 9 children: 'Your content here...' 10} 11 12// Rich content 13{ 14 id: 'article-content', 15 type: 'Markdown', 16 name: 'Article Body', 17 props: {}, 18 children: '# Article Title\n\nThis is **markdown** content.' 19} 20 21// Images 22{ 23 id: 'hero-image', 24 type: 'img', 25 name: 'Hero Image', 26 props: { 27 src: '/hero.jpg', 28 alt: 'Hero image', 29 className: 'w-full h-64 object-cover' 30 }, 31 children: [] 32}
Interactive Layers
Layers that users can interact with:
tsx1// Buttons 2{ 3 id: 'submit-btn', 4 type: 'Button', 5 name: 'Submit Button', 6 props: { 7 type: 'submit', 8 variant: 'default' 9 }, 10 children: 'Submit Form' 11} 12 13// Form inputs 14{ 15 id: 'email-input', 16 type: 'Input', 17 name: 'Email Field', 18 props: { 19 type: 'email', 20 placeholder: 'Enter your email', 21 className: 'w-full' 22 }, 23 children: [] 24}
Children Patterns
Layers can have different types of children:
Text Children
For simple text content:
tsx1{ 2 id: 'simple-text', 3 type: 'p', 4 name: 'Paragraph', 5 props: {}, 6 children: 'This is simple text content' // string 7}
Component Children
For nested components:
tsx1{ 2 id: 'container', 3 type: 'div', 4 name: 'Container', 5 props: {}, 6 children: [ // array of ComponentLayer objects 7 { 8 id: 'child-1', 9 type: 'span', 10 name: 'First Child', 11 props: {}, 12 children: 'Hello' 13 }, 14 { 15 id: 'child-2', 16 type: 'span', 17 name: 'Second Child', 18 props: {}, 19 children: 'World' 20 } 21 ] 22}
Empty Children
For self-closing elements:
tsx1{ 2 id: 'line-break', 3 type: 'br', 4 name: 'Line Break', 5 props: {}, 6 children: [] // empty array 7}
Best Practices
Unique IDs
Ensure every layer has a unique id
:
tsx1// ✅ Good - unique IDs 2{ id: 'header-logo', type: 'img', ... } 3{ id: 'nav-menu', type: 'nav', ... } 4{ id: 'footer-copyright', type: 'p', ... } 5 6// ❌ Bad - duplicate IDs 7{ id: 'button', type: 'Button', ... } 8{ id: 'button', type: 'Button', ... } // Duplicate!
Meaningful Names
Use descriptive names for the layers panel:
tsx1// ✅ Good - descriptive names 2{ id: 'hero-cta', name: 'Hero Call-to-Action', type: 'Button', ... } 3{ id: 'product-grid', name: 'Product Grid', type: 'div', ... } 4 5// ❌ Bad - generic names 6{ id: 'button-1', name: 'Button', type: 'Button', ... } 7{ id: 'div-2', name: 'div', type: 'div', ... }
Component Dependencies
Make sure all referenced component types exist in your registry:
tsx1// If your Button has span children, include span in registry 2const registry = { 3 ...primitiveComponentDefinitions, // includes 'span' 4 Button: { /* your button definition */ } 5};
Semantic Structure
Follow HTML semantic structure where possible:
tsx1// ✅ Good - semantic structure 2{ 3 id: 'article', 4 type: 'article', 5 name: 'Blog Post', 6 children: [ 7 { id: 'title', type: 'h1', name: 'Title', ... }, 8 { id: 'meta', type: 'div', name: 'Meta Info', ... }, 9 { id: 'content', type: 'div', name: 'Content', ... } 10 ] 11}
Related Topics
- Component Registry - Learn how to define which components are available
- Variable Binding - Make your layers dynamic with variables
- Rendering Pages - Render layers without the editor
- Persistence - Save and load layer structures