Files
metabuilder/docs/implementation/FAKEMUI_INTEGRATION.md
johndoe6345789 e717a1916b chore: Organize docs folder into logical subfolders
Grouped 100+ docs into categories:
- architecture/ - System design, DBAL, component architecture
- analysis/ - Status reports, assessments, migration analysis
- guides/ - Quick references, how-tos, integration guides
- implementation/ - Implementation details, migration guides
- packages/ - Package-specific docs (forum, notifications, etc)
- phases/ - Phase completion summaries and deliverables
- testing/ - E2E tests, Playwright, test architecture
- workflow/ - Workflow engine documentation

Root level retains: README, ROADMAP, AGENTS, CONTRACT, CLAUDE, PROMPT

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 17:55:28 +00:00

16 KiB

Fakemui Integration Guide

Complete guide to integrating fakemui components with the JSON component system.

Overview

The MetaBuilder frontend uses fakemui (Material-UI inspired component library) with a declarative JSON-based component system. This enables:

  • No hardcoded components - All UI defined in JSON
  • Data-driven rendering - Components rendered from database
  • Consistent styling - All components use fakemui Material Design
  • Package self-containment - Each package defines its own components
  • Runtime customization - Admins can modify component definitions without code changes

Architecture

Package Seed Data
  ↓
/packages/[packageId]/component/ui-components.json
  ↓
Schema Validation (component.schema.json)
  ↓
JSON Component Loader
  ↓
FAKEMUI_REGISTRY
  ↓
renderJSONComponent()
  ↓
Fakemui Components
  ↓
React Elements
  ↓
Browser

Components Available

131+ Fakemui Components Organized by Category

Category Count Components Status
Form 28 Button, TextField, Select, Checkbox, Radio, DatePicker, ColorPicker, etc. Ready
Display 26 Typography, Avatar, Badge, Chip, Tooltip, List, etc. Ready
Layout 18 Box, Grid, Stack, Flex, Card, Paper, etc. Ready
Navigation 22 Breadcrumbs, Pagination, Tabs, Stepper, Menu, etc. Ready
Modal 11 Modal, Drawer, Popover, Dialog, Accordion, AppBar, etc. Ready
Table 10 Table, TableHead, TableBody, DataGrid, etc. Ready
Icons 27 Plus, Trash, Copy, Check, Arrow icons, etc. Ready
Feedback 6 Alert, Snackbar, Skeleton, Spinner, etc. Ready
Advanced 3 Timeline, TreeView, Masonry, LoadingButton Ready

Total: 151 components available

Full Component Registry

Access the complete registry:

import { FAKEMUI_REGISTRY, FAKEMUI_CATEGORIES } from '@/lib/fakemui-registry'

// Get a specific component
const ButtonComponent = FAKEMUI_REGISTRY['Button']

// Get all components in a category
const formComponents = FAKEMUI_CATEGORIES['form']

// Check if component exists
const exists = 'Button' in FAKEMUI_REGISTRY

Creating JSON Components

Step 1: Define Component in Seed Data

Create /packages/my_package/component/ui-components.json:

[
  {
    "id": "comp_my_button",
    "name": "My Button",
    "description": "Primary action button",
    "category": "form",
    "version": "1.0.0",
    "isPublished": true,
    "schema": {
      "type": "object",
      "properties": {
        "label": { "type": "string", "default": "Click Me" },
        "variant": {
          "type": "string",
          "enum": ["primary", "secondary", "outline"],
          "default": "primary"
        },
        "disabled": { "type": "boolean", "default": false }
      }
    },
    "template": {
      "type": "Button",
      "props": {
        "variant": "{{variant}}",
        "disabled": "{{disabled}}"
      },
      "children": "{{label}}"
    },
    "props": {
      "label": "Click Me",
      "variant": "primary",
      "disabled": false
    },
    "events": [
      { "name": "onClick", "description": "Fired when clicked" }
    ]
  }
]

Step 2: Create Metadata File

Create /packages/my_package/component/metadata.json:

{
  "entityType": "component",
  "description": "My package components",
  "components": [
    {
      "id": "comp_my_button",
      "name": "My Button"
    }
  ]
}

Step 3: Use in Page Definition

In /packages/my_package/page-config/my-page.json:

[
  {
    "id": "page_my_page",
    "path": "/my-page",
    "title": "My Page",
    "component": "my_page_root",
    "componentTree": {
      "type": "Box",
      "children": [
        {
          "type": "comp_my_button",
          "props": {
            "label": "Save",
            "variant": "primary"
          }
        }
      ]
    }
  }
]

Template Syntax

Basic Syntax

{
  "type": "Button",
  "props": {
    "label": "Click Me"
  },
  "children": "Button Text"
}

Dynamic Values (Template Expressions)

{
  "type": "TextField",
  "props": {
    "label": "{{label}}",
    "placeholder": "{{placeholder}}",
    "value": "{{formData.email}}"
  }
}

Supported expressions:

  • {{variable}} - Simple property access
  • {{props.title}} - Nested property
  • {{state.isLoading}} - State access
  • {{value ? 'Yes' : 'No'}} - Ternary operator
  • {{!disabled}} - Negation

Conditional Rendering

{
  "type": "conditional",
  "condition": "{{isLoading}}",
  "then": {
    "type": "Spinner"
  },
  "else": {
    "type": "Button",
    "children": "Save"
  }
}

Arrays and Iteration

{
  "type": "Box",
  "children": [
    {
      "type": "Typography",
      "children": "Item 1"
    },
    {
      "type": "Typography",
      "children": "Item 2"
    },
    {
      "type": "Typography",
      "children": "Item 3"
    }
  ]
}

Fakemui Component Examples

Button Component

{
  "id": "comp_action_button",
  "name": "Action Button",
  "category": "form",
  "template": {
    "type": "Button",
    "props": {
      "variant": "{{variant}}",
      "size": "{{size}}",
      "disabled": "{{disabled}}",
      "loading": "{{loading}}",
      "fullWidth": "{{fullWidth}}"
    },
    "children": "{{label}}"
  },
  "props": {
    "label": "Click",
    "variant": "primary",
    "size": "md",
    "disabled": false,
    "loading": false,
    "fullWidth": false
  }
}

Card Component

{
  "id": "comp_feature_card",
  "name": "Feature Card",
  "category": "layout",
  "template": {
    "type": "Card",
    "children": [
      {
        "type": "CardMedia",
        "props": {
          "component": "img",
          "height": "200",
          "image": "{{image}}"
        }
      },
      {
        "type": "CardContent",
        "children": [
          {
            "type": "Typography",
            "props": { "variant": "h5", "component": "div" },
            "children": "{{title}}"
          },
          {
            "type": "Typography",
            "props": { "variant": "body2", "color": "textSecondary" },
            "children": "{{description}}"
          }
        ]
      },
      {
        "type": "CardActions",
        "children": [
          {
            "type": "Button",
            "props": { "size": "small" },
            "children": "Learn More"
          }
        ]
      }
    ]
  },
  "props": {
    "image": "/default-image.jpg",
    "title": "Feature",
    "description": "Feature description"
  }
}

Form Component

{
  "id": "comp_login_form",
  "name": "Login Form",
  "category": "form",
  "template": {
    "type": "Box",
    "style": { "maxWidth": "400px", "margin": "0 auto" },
    "children": [
      {
        "type": "TextField",
        "props": {
          "label": "Email",
          "type": "email",
          "fullWidth": true,
          "margin": "normal"
        }
      },
      {
        "type": "TextField",
        "props": {
          "label": "Password",
          "type": "password",
          "fullWidth": true,
          "margin": "normal"
        }
      },
      {
        "type": "Button",
        "props": {
          "variant": "contained",
          "fullWidth": true,
          "sx": { "mt": 3, "mb": 2 }
        },
        "children": "Sign In"
      }
    ]
  }
}

Grid Layout

{
  "id": "comp_feature_grid",
  "name": "Feature Grid",
  "category": "layout",
  "template": {
    "type": "Grid",
    "props": { "container": true, "spacing": 2 },
    "children": [
      {
        "type": "Grid",
        "props": { "item": true, "xs": 12, "sm": 6, "md": 4 },
        "children": {
          "type": "Card",
          "children": [
            {
              "type": "CardContent",
              "children": {
                "type": "Typography",
                "children": "Feature 1"
              }
            }
          ]
        }
      },
      {
        "type": "Grid",
        "props": { "item": true, "xs": 12, "sm": 6, "md": 4 },
        "children": {
          "type": "Card",
          "children": [
            {
              "type": "CardContent",
              "children": {
                "type": "Typography",
                "children": "Feature 2"
              }
            }
          ]
        }
      },
      {
        "type": "Grid",
        "props": { "item": true, "xs": 12, "sm": 6, "md": 4 },
        "children": {
          "type": "Card",
          "children": [
            {
              "type": "CardContent",
              "children": {
                "type": "Typography",
                "children": "Feature 3"
              }
            }
          ]
        }
      }
    ]
  }
}

Rendering Components

In React Component

import { renderJSONComponent } from '@/lib/packages/json/render-json-component'
import type { JSONComponent } from '@/lib/packages/json/types'

export function MyComponent({ componentDef }: { componentDef: JSONComponent }) {
  return renderJSONComponent(componentDef, {
    label: 'Custom Label',
    isLoading: false,
  })
}

With Custom Component Registry

import { renderJSONComponent } from '@/lib/packages/json/render-json-component'
import { FAKEMUI_REGISTRY } from '@/lib/fakemui-registry'

const customRegistry = {
  ...FAKEMUI_REGISTRY,
  CustomButton: MyCustomButton,
}

return renderJSONComponent(componentDef, props, customRegistry)

Real-World Examples

Home Page Hero Section

[
  {
    "id": "page_home",
    "path": "/",
    "title": "Home",
    "component": "home_root",
    "componentTree": {
      "type": "Box",
      "children": [
        {
          "type": "Box",
          "style": {
            "background": "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
            "color": "white",
            "padding": "4rem 2rem",
            "textAlign": "center"
          },
          "children": [
            {
              "type": "Typography",
              "props": { "variant": "h1" },
              "style": { "marginBottom": "1rem", "fontSize": "3rem" },
              "children": "MetaBuilder"
            },
            {
              "type": "Typography",
              "props": { "variant": "h5" },
              "style": { "marginBottom": "2rem" },
              "children": "Data-driven application platform"
            },
            {
              "type": "Button",
              "props": { "variant": "contained", "size": "lg" },
              "children": "Get Started"
            }
          ]
        }
      ]
    }
  }
]

Data Table Component

{
  "id": "comp_users_table",
  "name": "Users Table",
  "category": "table",
  "template": {
    "type": "TableContainer",
    "children": {
      "type": "Table",
      "children": [
        {
          "type": "TableHead",
          "children": {
            "type": "TableRow",
            "children": [
              {
                "type": "TableCell",
                "children": "Name"
              },
              {
                "type": "TableCell",
                "children": "Email"
              },
              {
                "type": "TableCell",
                "children": "Role"
              }
            ]
          }
        },
        {
          "type": "TableBody",
          "children": [
            {
              "type": "TableRow",
              "children": [
                {
                  "type": "TableCell",
                  "children": "{{users[0].name}}"
                },
                {
                  "type": "TableCell",
                  "children": "{{users[0].email}}"
                },
                {
                  "type": "TableCell",
                  "children": "{{users[0].role}}"
                }
              ]
            }
          ]
        }
      ]
    }
  }
}

Best Practices

1. Use Semantic Components

// ✅ GOOD - Use semantic components
{
  "type": "Button",
  "props": { "variant": "primary" },
  "children": "Save"
}

// ❌ AVOID - Don't hardcode divs
{
  "type": "div",
  "style": { "backgroundColor": "blue", "color": "white", "cursor": "pointer" },
  "children": "Save"
}

2. Leverage Props and State

// ✅ GOOD - Use template expressions
{
  "type": "Button",
  "props": {
    "disabled": "{{isLoading}}",
    "loading": "{{isLoading}}"
  },
  "children": "{{isLoading ? 'Saving...' : 'Save'}}"
}

// ❌ AVOID - Don't hardcode values
{
  "type": "Button",
  "props": { "disabled": false },
  "children": "Save"
}

3. Organize Components by Package

packages/ui_header/component/
  ├── metadata.json
  └── header-components.json

packages/ui_footer/component/
  ├── metadata.json
  └── footer-components.json

packages/dashboard/component/
  ├── metadata.json
  └── dashboard-components.json

4. Use Consistent Naming

// ✅ GOOD
{
  "id": "comp_header_navbar",
  "name": "Header Navigation Bar"
}

// ❌ AVOID
{
  "id": "nav1",
  "name": "Nav"
}

5. Document Props

{
  "id": "comp_feature_card",
  "name": "Feature Card",
  "description": "Displays a feature with icon, title, and description",
  "schema": {
    "type": "object",
    "properties": {
      "icon": {
        "type": "string",
        "description": "Icon name (Star, Heart, etc.)",
        "default": "Star"
      },
      "title": {
        "type": "string",
        "description": "Card title",
        "minLength": 1
      },
      "description": {
        "type": "string",
        "description": "Card description text"
      }
    }
  }
}

Troubleshooting

Component Not Rendering

Problem: Component renders but is blank Solution: Check that template is defined in component definition

{
  "id": "comp_my_component",
  "name": "My Component",
  "template": {  // ← Required
    "type": "Box",
    "children": "..."
  }
}

Template Expression Not Working

Problem: {{variable}} showing literally in output Solution: Ensure props are passed to renderer

// Make sure props match template expressions
renderJSONComponent(componentDef, {
  variable: 'actual value'  // ← Must be provided
})

Component Not in Registry

Problem: Error "Component [Name] not found" Solution: Verify component is exported from fakemui

import { FAKEMUI_REGISTRY } from '@/lib/fakemui-registry'
console.log(Object.keys(FAKEMUI_REGISTRY))  // List all available

Migration Guide

From Hardcoded Components to JSON

Before (Hardcoded):

export function HomePage() {
  return (
    <Box>
      <Typography variant="h1">Home</Typography>
      <Button variant="primary">Get Started</Button>
    </Box>
  )
}

After (JSON-based):

// packages/ui_home/component/home-components.json
[
  {
    "id": "comp_home_hero",
    "template": {
      "type": "Box",
      "children": [
        { "type": "Typography", "props": { "variant": "h1" }, "children": "Home" },
        { "type": "Button", "props": { "variant": "primary" }, "children": "Get Started" }
      ]
    }
  }
]

// Frontend loads from database and renders
export function HomePage() {
  const component = await db.components.findOne({ id: 'comp_home_hero' })
  return renderJSONComponent(component)
}

References

  • Fakemui Components: 131+ Material Design components
  • Component Schema: /schemas/package-schemas/component.schema.json
  • Registry: /frontends/nextjs/src/lib/fakemui-registry.ts
  • Renderer: /frontends/nextjs/src/lib/packages/json/render-json-component.tsx
  • Examples: /packages/ui_home/component/ui-components.json

Last Updated: 2026-01-16 Version: 1.0.0 Status: Production Ready