| title | ObjectUI - UI Layer Architecture |
|---|---|
| description | Deep dive into the ObjectUI (Server-Driven UI) protocol architecture |
Deep dive into the ObjectUI (Server-Driven UI) protocol architecture
ObjectUI is the presentation protocol that defines how user interfaces are configured and rendered. It enables building dynamic UIs without hardcoding components.
Defines the top-level application configuration:
const app = {
name: 'sales_app',
label: 'Sales CRM',
branding: {
logo: '/assets/logo.png',
primaryColor: '#0066CC',
secondaryColor: '#FF6B00',
},
navigation: [
{ type: 'object', object: 'customer_account', label: 'Accounts' },
{ type: 'object', object: 'opportunity', label: 'Opportunities' },
{ type: 'dashboard', dashboard: 'sales_dashboard', label: 'Dashboard' },
],
};Display collections of records:
Grid View - Tabular data display:
{
type: 'grid',
columns: ['name', 'email', 'revenue', 'status'],
filters: ['status:active'],
sortBy: 'revenue:desc',
pageSize: 25,
}Kanban View - Card-based workflow:
{
type: 'kanban',
groupByField: 'status',
cardTitle: 'name',
cardFields: ['email', 'revenue'],
}Calendar View - Time-based display:
{
type: 'calendar',
dateField: 'event_date',
titleField: 'name',
defaultView: 'month',
}Gantt View - Timeline and dependencies:
{
type: 'gantt',
startDateField: 'start_date',
endDateField: 'end_date',
titleField: 'task_name',
parentField: 'parent_task',
}Display/edit single records:
Simple Form - Basic layout:
{
type: 'simple',
sections: [
{
title: 'Basic Information',
columns: 2,
fields: ['name', 'email', 'phone'],
}
],
}Tabbed Form - Organized by tabs:
{
type: 'tabbed',
tabs: [
{ title: 'Details', fields: ['name', 'email'] },
{ title: 'Address', fields: ['street', 'city', 'country'] },
],
}Wizard Form - Multi-step process:
{
type: 'wizard',
steps: [
{ title: 'Step 1', fields: ['name', 'email'] },
{ title: 'Step 2', fields: ['company', 'role'] },
],
}Data analysis and visualization:
const report = {
type: 'tabular',
object: 'customer_account',
columns: ['name', 'industry', 'revenue'],
groupBy: ['industry'],
aggregations: [
{ field: 'revenue', function: 'SUM' },
{ field: 'id', function: 'COUNT' },
],
filters: [{ field: 'status', operator: 'eq', value: 'active' }],
sortBy: [{ field: 'revenue', direction: 'desc' }],
};Multiple widgets in a grid layout:
const dashboard = {
name: 'sales_dashboard',
label: 'Sales Dashboard',
layout: [
{ x: 0, y: 0, w: 6, h: 4, widget: 'revenue_chart' },
{ x: 6, y: 0, w: 6, h: 4, widget: 'pipeline_summary' },
{ x: 0, y: 4, w: 12, h: 6, widget: 'top_accounts' },
],
widgets: [
{
id: 'revenue_chart',
type: 'chart',
chartType: 'line',
report: 'monthly_revenue',
},
{
id: 'pipeline_summary',
type: 'metric',
label: 'Pipeline Value',
aggregation: { field: 'amount', function: 'SUM' },
},
],
};Consistent design system:
const theme = {
colors: {
primary: '#0066CC',
secondary: '#FF6B00',
success: '#28A745',
warning: '#FFC107',
error: '#DC3545',
background: '#FFFFFF',
surface: '#F8F9FA',
text: '#212529',
},
typography: {
fontFamily: 'Inter, sans-serif',
fontSize: {
xs: '0.75rem',
sm: '0.875rem',
base: '1rem',
lg: '1.125rem',
xl: '1.25rem',
},
},
spacing: {
xs: '0.25rem',
sm: '0.5rem',
md: '1rem',
lg: '1.5rem',
xl: '2rem',
},
borderRadius: {
sm: '0.25rem',
md: '0.5rem',
lg: '1rem',
},
};User-triggered operations:
const action = {
name: 'approve_record',
label: 'Approve',
type: 'flow',
flowName: 'approval_flow',
confirmMessage: 'Are you sure you want to approve this record?',
successMessage: 'Record approved successfully',
icon: 'check',
variant: 'primary',
};┌─────────────────────────────────────────────────────────┐
│ User Action (Navigate, Click, Edit) │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ UI Protocol Resolver │
│ - Resolves view configuration │
│ - Fetches object metadata │
│ - Checks user permissions │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Data Fetcher (ObjectQL) │
│ - Builds query from view config │
│ - Executes query via driver │
│ - Returns data with metadata │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Renderer (React, Vue, etc.) │
│ - Renders components from protocol │
│ - Applies theme configuration │
│ - Binds data to UI elements │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Browser / Mobile App │
└─────────────────────────────────────────────────────────┘
Custom field rendering:
interface FieldWidgetProps {
value: any;
onChange: (value: any) => void;
field: Field;
readonly: boolean;
required: boolean;
error?: string;
}
// Example: Custom email field widget
const EmailWidget: React.FC<FieldWidgetProps> = (props) => {
return (
<input
type="email"
value={props.value || ''}
onChange={(e) => props.onChange(e.target.value)}
disabled={props.readonly}
required={props.required}
className={props.error ? 'error' : ''}
/>
);
};Flexible page composition:
const page = {
name: 'account_detail',
label: 'Account Details',
regions: [
{
name: 'header',
components: [
{ type: 'record_header', showActions: true },
],
},
{
name: 'main',
columns: [
{
components: [
{ type: 'record_detail', layout: 'two_column' },
{ type: 'related_list', relatedObject: 'opportunity' },
],
},
{
components: [
{ type: 'activity_timeline' },
{ type: 'chatter_feed' },
],
},
],
},
],
};-
View Configuration
- Keep views focused and simple
- Use appropriate view types for data
- Optimize column count for readability
- Provide meaningful default filters
-
Form Design
- Group related fields in sections
- Use 2-column layouts for efficiency
- Show only necessary fields
- Provide clear labels and help text
-
Dashboard Design
- Limit widgets to 6-8 per dashboard
- Use consistent chart types
- Provide drill-down capabilities
- Update data in real-time or near-real-time
-
Theme Consistency
- Use design tokens
- Maintain color contrast ratios
- Follow accessibility guidelines
- Test on multiple screen sizes
-
Performance
- Lazy load components
- Paginate large lists
- Cache view configurations
- Minimize re-renders
For complete API reference, see UI Protocol References.