ObjectUIObjectUI
Core

Application Schema (AppSchema)

Configure your entire application with navigation, branding, and global settings

Application Schema

The AppSchema defines the top-level configuration for your entire ObjectUI application, including navigation menus, branding, layout strategies, and global actions.

Overview

AppSchema provides a declarative way to configure:

  • Navigation menus - Hierarchical menu structures with icons and badges
  • Branding - Logo, title, favicon
  • Layout strategies - Sidebar, header, or empty layout
  • Global actions - User menu, global toolbar buttons

Interactive Examples

Sidebar Navigation

A typical application sidebar menu structure with icons, groups, and badges

128
{
  "type": "card",
  "className": "w-64",
  "children": [
    {
      "type": "stack",
      "spacing": 1,
      "children": [
        {
          "type": "flex",
          "className": "items-center gap-2 px-3 py-2 rounded-md bg-accent text-accent-foreground",
          "children": [
            {
              "type": "icon",
              "name": "layout-dashboard",
              "className": "h-4 w-4"
            },
            {
              "type": "text",
              "content": "Dashboard",
              "className": "text-sm font-medium"
            }
          ]
        },
        {
          "type": "flex",
          "className": "items-center gap-2 px-3 py-2 rounded-md hover:bg-accent/50",
          "children": [
            {
              "type": "icon",
              "name": "users",
              "className": "h-4 w-4 text-muted-foreground"
            },
            {
              "type": "text",
              "content": "Contacts",
              "className": "text-sm"
            },
            {
              "type": "badge",
              "label": "128",
              "variant": "secondary",
              "className": "ml-auto text-xs"
            }
          ]
        },
        {
          "type": "flex",
          "className": "items-center gap-2 px-3 py-2 rounded-md hover:bg-accent/50",
          "children": [
            {
              "type": "icon",
              "name": "target",
              "className": "h-4 w-4 text-muted-foreground"
            },
            {
              "type": "text",
              "content": "Opportunities",
              "className": "text-sm"
            }
          ]
        },
        {
          "type": "separator",
          "className": "my-2"
        },
        {
          "type": "text",
          "content": "Marketing",
          "className": "px-3 text-xs font-semibold text-muted-foreground uppercase tracking-wider"
        },
        {
          "type": "flex",
          "className": "items-center gap-2 px-3 py-2 rounded-md hover:bg-accent/50",
          "children": [
            {
              "type": "icon",
              "name": "megaphone",
              "className": "h-4 w-4 text-muted-foreground"
            },
            {
              "type": "text",
              "content": "Campaigns",
              "className": "text-sm"
            }
          ]
        },
        {
          "type": "flex",
          "className": "items-center gap-2 px-3 py-2 rounded-md hover:bg-accent/50",
          "children": [
            {
              "type": "icon",
              "name": "mail",
              "className": "h-4 w-4 text-muted-foreground"
            },
            {
              "type": "text",
              "content": "Email Templates",
              "className": "text-sm"
            }
          ]
        },
        {
          "type": "separator",
          "className": "my-2"
        },
        {
          "type": "flex",
          "className": "items-center gap-2 px-3 py-2 rounded-md hover:bg-accent/50",
          "children": [
            {
              "type": "icon",
              "name": "settings",
              "className": "h-4 w-4 text-muted-foreground"
            },
            {
              "type": "text",
              "content": "Settings",
              "className": "text-sm"
            }
          ]
        }
      ]
    }
  ]
}

Application Header Bar

Application Header

Top bar with branding, global search, and user actions

U

PNG, JPG up to 5MB

{
  "type": "flex",
  "className": "items-center justify-between p-3 border rounded-lg bg-background",
  "children": [
    {
      "type": "flex",
      "className": "items-center gap-3",
      "children": [
        {
          "type": "icon",
          "name": "box",
          "className": "h-6 w-6 text-primary"
        },
        {
          "type": "text",
          "content": "Acme CRM",
          "className": "font-semibold text-lg"
        }
      ]
    },
    {
      "type": "flex",
      "className": "items-center gap-2",
      "children": [
        {
          "type": "button",
          "label": "Quick Actions",
          "variant": "outline",
          "size": "sm",
          "icon": "zap"
        },
        {
          "type": "button",
          "label": "Notifications",
          "variant": "ghost",
          "size": "sm",
          "icon": "bell"
        },
        {
          "type": "flex",
          "className": "items-center gap-2 ml-2 pl-2 border-l",
          "children": [
            {
              "type": "avatar",
              "fallback": "JD",
              "className": "h-8 w-8"
            },
            {
              "type": "stack",
              "spacing": 0,
              "children": [
                {
                  "type": "text",
                  "content": "John Doe",
                  "className": "text-sm font-medium leading-none"
                },
                {
                  "type": "text",
                  "content": "john@acme.com",
                  "className": "text-xs text-muted-foreground"
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

Basic Usage

import type { AppSchema } from '@object-ui/types';

const app: AppSchema = {
  type: 'app',
  name: 'my-crm',
  title: 'My CRM Application',
  logo: '/logo.svg',
  favicon: '/favicon.ico',
  layout: 'sidebar',
  
  menu: [
    {
      type: 'item',
      label: 'Dashboard',
      icon: 'layout-dashboard',
      path: '/dashboard'
    }
  ],
  
  actions: [
    {
      type: 'user',
      label: 'John Doe',
      avatar: '/avatar.jpg'
    }
  ]
};

Properties

Basic Configuration

PropertyTypeDescription
type'app'Component type identifier (required)
namestringApplication system identifier
titlestringDisplay title shown in browser
descriptionstringApplication description
logostringLogo URL or icon name
faviconstringFavicon URL

Layout Configuration

PropertyTypeDefaultDescription
layout'sidebar' | 'header' | 'empty''sidebar'Global layout strategy

Layout Options:

  • sidebar - Standard admin layout with left sidebar navigation
  • header - Top navigation bar only
  • empty - No layout, pages handle their own structure

The menu property accepts an array of MenuItem objects:

interface MenuItem {
  type?: 'item' | 'group' | 'separator';
  label?: string;
  icon?: string;          // Lucide icon name
  path?: string;          // Route path
  href?: string;          // External link
  children?: MenuItem[];  // Submenu items
  badge?: string | number;
  hidden?: boolean | string; // Visibility condition
}

Item - Single navigation link

{
  "type": "item",
  "label": "Dashboard",
  "icon": "layout-dashboard",
  "path": "/dashboard",
  "badge": "New"
}

Group - Collapsible menu group

{
  "type": "group",
  "label": "Sales",
  "icon": "dollar-sign",
  "children": [
    { "type": "item", "label": "Leads", "path": "/leads" },
    { "type": "item", "label": "Deals", "path": "/deals" }
  ]
}

Separator - Visual separator

{
  "type": "separator"
}

Global Actions

The actions property defines global toolbar buttons:

interface AppAction {
  type: 'button' | 'dropdown' | 'user';
  label?: string;
  icon?: string;
  onClick?: string;
  avatar?: string;        // For type='user'
  description?: string;   // For type='user'
  items?: MenuItem[];     // For type='dropdown' or 'user'
  shortcut?: string;      // Keyboard shortcut
  variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link';
  size?: 'default' | 'sm' | 'lg' | 'icon';
}

Complete Example

const crm: AppSchema = {
  type: 'app',
  name: 'acme-crm',
  title: 'Acme CRM',
  description: 'Customer Relationship Management System',
  logo: '/acme-logo.svg',
  favicon: '/favicon.ico',
  layout: 'sidebar',
  
  menu: [
    {
      type: 'item',
      label: 'Dashboard',
      icon: 'layout-dashboard',
      path: '/dashboard'
    },
    {
      type: 'separator'
    },
    {
      type: 'group',
      label: 'Sales',
      icon: 'dollar-sign',
      children: [
        {
          type: 'item',
          label: 'Leads',
          icon: 'users',
          path: '/leads',
          badge: 12
        },
        {
          type: 'item',
          label: 'Opportunities',
          icon: 'target',
          path: '/opportunities'
        },
        {
          type: 'item',
          label: 'Quotes',
          icon: 'file-text',
          path: '/quotes'
        }
      ]
    },
    {
      type: 'group',
      label: 'Marketing',
      icon: 'megaphone',
      children: [
        {
          type: 'item',
          label: 'Campaigns',
          path: '/campaigns'
        },
        {
          type: 'item',
          label: 'Email Templates',
          path: '/templates'
        }
      ]
    },
    {
      type: 'separator'
    },
    {
      type: 'item',
      label: 'Settings',
      icon: 'settings',
      path: '/settings',
      hidden: '${user.role !== "admin"}'
    }
  ],
  
  actions: [
    {
      type: 'button',
      label: 'Quick Actions',
      icon: 'zap',
      variant: 'outline',
      onClick: 'openQuickActions'
    },
    {
      type: 'user',
      label: 'John Doe',
      avatar: '/avatars/john.jpg',
      description: 'john@acme.com',
      items: [
        {
          type: 'item',
          label: 'Profile',
          icon: 'user',
          path: '/profile'
        },
        {
          type: 'item',
          label: 'Settings',
          icon: 'settings',
          path: '/settings'
        },
        {
          type: 'separator'
        },
        {
          type: 'item',
          label: 'Logout',
          icon: 'log-out',
          path: '/logout'
        }
      ]
    }
  ]
};

Runtime Validation

Use Zod validation to ensure your app configuration is correct:

import { AppSchema } from '@object-ui/types/zod';

const result = AppSchema.safeParse(myAppConfig);

if (result.success) {
  console.log('Valid app configuration');
} else {
  console.error('Validation errors:', result.error);
}

Conditional Navigation

Use expression syntax to show/hide menu items based on user permissions:

{
  "type": "item",
  "label": "Admin Panel",
  "path": "/admin",
  "hidden": "${user.role !== 'admin'}"
}

Use Cases

AppSchema is ideal for:

  • Multi-page applications - Configure complex application structures with multiple routes
  • Admin dashboards - Create comprehensive admin panels with role-based navigation
  • CRM systems - Build customer relationship management interfaces
  • Internal tools - Develop enterprise internal tools with centralized navigation
  • SaaS products - Configure multi-tenant applications with customizable layouts

Best Practices

  1. Use semantic icons - Choose Lucide icons that clearly represent the section
  2. Group related items - Use menu groups to organize navigation
  3. Limit top-level items - Keep the main menu concise (5-7 items)
  4. Add badges for notifications - Show counts or status indicators
  5. Hide admin features - Use conditional visibility for role-based access
  6. Provide keyboard shortcuts - Add shortcuts for frequently used actions

On this page