Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
319 changes: 284 additions & 35 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,309 @@
layout: home

hero:
name: Object UI
text: The Universal UI Engine
tagline: Build Enterprise Interfaces with JSON. Render with React, Style with Tailwind.
name: ObjectUI
text: Stop Hand-Coding Enterprise UIs
tagline: A Server-Driven UI Engine that turns JSON into pixel-perfect React + Tailwind + Shadcn components. Build complex dashboards, forms, and data views faster—without sacrificing design quality or flexibility.
actions:
- theme: brand
text: Quick Start
link: /guide/introduction
text: Read the Spec
link: /protocol/overview
- theme: alt
text: Architecture
link: /spec/architecture
text: View Component Gallery
link: /components/

features:
- title: 🎨 Tailwind Native
details: Fully stylable using standard Utility Classes. No hidden styles or CSS modules. Merge styles via `className`.
- title: 🔌 Backend Agnostic
details: Connect to Rest, GraphQL, or Local Data. Universal `DataSource` interface allows usage with any API.
- title: 🧱 Shadcn Compatible
details: Built on Radix UI primitives. The rendered output looks and feels like hand-coded Shadcn components.
- title: ⚡️ Lazy Loaded Plugins
details: Heavy components (Monaco, Recharts) are loaded only when rendered, keeping your bundle ultra-light.
- title: 🎨 The Stack You Love
details: Built on React, Radix primitives (Shadcn), and native Tailwind CSS. Not a black box—override styles with utility classes. No hidden CSS modules. Just pure, modern frontend tech.
- title: ⚡️ Server-Driven Agility
details: Update layouts, fields, and validation rules instantly from your backend—no frontend redeployment needed. Change a form in production? Just update the JSON. The UI adapts in real-time.
- title: 🏢 Enterprise Ready-Made
details: Built-in support for complex patterns like Kanbans, Gantt charts, multi-step forms, and data tables with sorting/filtering. Stop rebuilding the same components from scratch.
---

# The Shift to Schema-Driven UI
# You Define the Intent. We Render the Reality.

Object UI decouples the **Protocol** (JSON Schema) from the **Implementation** (React Components), allowing you to build complex enterprise apps faster without sacrificing control.
Frontend development for enterprise apps is repetitive. You spend 80% of your time gluing together form libraries, data tables, and validation logic—writing the same boilerplate over and over.

## How it works
**ObjectUI turns UI into Data.** Define your interface in standard JSON, and let our engine render pixel-perfect, accessible React + Tailwind components.

### 1. Define Protocol (JSON)
You define the *what*, not the *how*. Standard Tailwind classes apply directly.
---

## The Magic Trick: JSON → Beautiful UI

ObjectUI bridges the gap between configuration speed and design quality. Here's how:

### Input: The Protocol (JSON Schema)

You define **what** you want, not **how** to build it. Standard Tailwind classes work natively.

```json
{
"type": "form",
"className": "space-y-4 border p-4 rounded-lg",
"fields": [
"type": "data-table",
"className": "rounded-lg border",
"dataSource": {
"api": "/api/users",
"method": "GET"
},
"columns": [
{
"key": "name",
"title": "User Name",
"sortable": true
},
{
"key": "email",
"title": "Email Address"
},
{
"type": "input",
"name": "email",
"label": "Email Address",
"className": "bg-slate-50"
"key": "status",
"title": "Status",
"render": "badge"
}
],
"actions": [
{
"label": "Edit",
"type": "button",
"variant": "outline",
"onClick": {
"action": "navigate",
"target": "/users/${row.id}/edit"
}
}
]
Comment on lines +65 to 75
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JSON schema example shows an actions array with an onClick handler structure that doesn't match the actual DataTableSchema type definition. According to the types in packages/types/src/data-display.ts, the DataTableSchema interface doesn't have an actions property. Instead, it uses onRowEdit and onRowDelete callback handlers.

The example also shows onClick with an object containing action and target properties, but the actual EventHandler interface (from api-types.ts) uses type and navigate properties for navigation actions.

Update the example to match the actual schema implementation, or if this represents future functionality, add a note indicating this is a planned feature.

Suggested change
"actions": [
{
"label": "Edit",
"type": "button",
"variant": "outline",
"onClick": {
"action": "navigate",
"target": "/users/${row.id}/edit"
}
}
]
"onRowEdit": {
"type": "navigate",
"navigate": "/users/${row.id}/edit"
}

Copilot uses AI. Check for mistakes.
}
```

### 2. Render Component (React)
The engine transforms generic JSON into polished **Shadcn UI** components.
### Output: Production-Ready Shadcn Component

The engine transforms your JSON into a **fully interactive, accessible data table** with:

- ✅ Server-side data fetching
- ✅ Column sorting and filtering
- ✅ Action buttons with dynamic routing
- ✅ Responsive design (mobile-friendly)
- ✅ Light/dark theme support
- ✅ WCAG 2.1 AA accessibility

**All rendered using the same Shadcn UI primitives you'd hand-code**, but configured in seconds instead of hours.

---

## Why ObjectUI?

### 1. The Stack You Love 🎨

ObjectUI is **not a proprietary framework**. It's built on the modern frontend stack you already know and trust:

- **React 18+** with hooks and concurrent rendering
- **Radix UI primitives** (the foundation of Shadcn)
- **Tailwind CSS** for styling—use utility classes directly in your JSON
- **TypeScript-first** with complete type definitions

**You're not locked into a black box.** Every component ObjectUI renders looks and behaves like hand-coded Shadcn UI. You can:

- Override styles using `className` with Tailwind utilities
- Inspect the rendered DOM—it's just clean React + Radix
- Mix ObjectUI with your existing React codebase seamlessly

### 2. Server-Driven Agility ⚡️

In traditional frontend development, changing a form field requires:

1. Editing React code
2. Running tests
3. Building the app
4. Deploying to production

With **Server-Driven UI (SDUI)**, the UI is a **configuration**, not code. ObjectUI separates the **protocol** (what to render) from the **implementation** (how to render it).

**The Benefits:**

- **Instant Updates:** Change layouts, fields, or validation rules from your backend—no frontend redeployment
- **A/B Testing:** Serve different UI schemas to different users dynamically
- **Multi-tenant Apps:** Each client gets a customized interface from the same codebase
- **Backend-Driven Validation:** Form rules defined server-side, enforced client-side automatically

**Example:** Your backend returns a JSON schema. The UI adapts instantly.

```typescript
// Backend returns this JSON
const schema = await fetch('/api/dashboard/schema').then(r => r.json());

// React renders it
<SchemaRenderer schema={schema} />
```

Change the schema on the backend? The dashboard updates in production—**no code push required.**

### 3. Enterprise Ready-Made 🏢

Stop rebuilding the same complex components from scratch. ObjectUI includes production-ready patterns for:

- **📊 Data Tables** with sorting, filtering, pagination, and bulk actions
- **📋 Multi-step Forms** with validation, conditional fields, and auto-save
- **🗂️ Kanban Boards** with drag-and-drop and swimlanes
- **📅 Gantt Charts** for project planning
- **📈 Dashboards** with metrics, charts, and real-time updates
- **🔍 Advanced Filters** with dynamic operators and query builders

All components are:

- **Accessible** (WCAG 2.1 AA compliant)
- **Responsive** (mobile-first design)
- **Themeable** (light/dark mode built-in)
- **Performant** (lazy-loaded, tree-shakable)

---

## How It Works: The Architecture

ObjectUI follows a clean, three-layer architecture:

### Step 1: The Protocol (JSON Schema)

You define the UI structure using a **standard JSON protocol**. This is the **source of truth** for your interface.

```json
{
"type": "page",
"title": "User Dashboard",
"body": {
"type": "grid",
"columns": 3,
"items": [...]
}
}
```

The protocol is **backend-agnostic**. Serve it from REST, GraphQL, or even static files.

### Step 2: The Engine (@object-ui/core)

The **core engine** processes the schema:

- **Validates** the JSON structure
- **Resolves** expressions like `visible: "${user.role === 'admin'}"`
- **Manages** component state and data flow
- **Registers** custom components

**Zero React dependencies.** The core is pure TypeScript logic—fully testable, fully portable.

Comment on lines +189 to +193
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation states that @object-ui/core has "Zero React dependencies" and is "pure TypeScript logic." However, it also claims that custom components can be registered using registerRenderer from @object-ui/core.

Based on the codebase examination, the actual API is ComponentRegistry.register() from @object-ui/core, and the component registry accepts React components. This creates a conceptual inconsistency - if core is truly React-free, it shouldn't be importing or registering React components directly.

Consider clarifying that while the core logic (validation, expressions) is React-free, the component registry is part of the bridge layer that connects to React components.

Suggested change
- **Manages** component state and data flow
- **Registers** custom components
**Zero React dependencies.** The core is pure TypeScript logic—fully testable, fully portable.
- **Manages** component state, expressions, and data flow
The engine is implemented as **pure TypeScript logic** and can run fully outside of React (Node.js, edge runtimes, tests) for validation, expression evaluation, and action handling.
> Note: React-specific concerns—like wiring `"type"` strings to concrete React components and registering custom renderers—live in the runtime/bridge layer, not in the core logic. This keeps `@object-ui/core` React-free while still allowing you to plug in your own React components where you render the schema.

Copilot uses AI. Check for mistakes.
### Step 3: The Renderer (@object-ui/react)

The **React runtime** maps JSON nodes to Shadcn components:

```typescript
import { SchemaRenderer } from '@object-ui/react';

<SchemaRenderer schema={schema} data={data} />
```

Under the hood, ObjectUI uses the **component registry** to find the right React component for each schema type (e.g., `"type": "data-table"``<DataTable />`).

The rendered output is **indistinguishable** from hand-coded Shadcn UI.

---

## Not Just a Toy: Extensibility

**Worried about being locked in?** Don't be.

ObjectUI is designed for **professional developers** who need flexibility. You can:

### Register Custom React Components

Have a specialized component your design system requires? Register it into the engine and use it in your JSON schemas.

```typescript
import { registerRenderer } from '@object-ui/core';
import { MyCustomWidget } from './components/MyCustomWidget';

// Register your custom component
registerRenderer('custom-widget', MyCustomWidget);
Comment on lines +221 to +225
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function registerRenderer does not exist in the @object-ui/core package. Based on the actual codebase, the correct API is either:

  1. ComponentRegistry.register() (imported from @object-ui/core)
  2. getComponentRegistry().register() (imported from @object-ui/react)

This inconsistency could confuse developers trying to use the documented API. Update to use the actual API that exists in the codebase.

Suggested change
import { registerRenderer } from '@object-ui/core';
import { MyCustomWidget } from './components/MyCustomWidget';
// Register your custom component
registerRenderer('custom-widget', MyCustomWidget);
import { ComponentRegistry } from '@object-ui/core';
import { MyCustomWidget } from './components/MyCustomWidget';
// Register your custom component
ComponentRegistry.register('custom-widget', MyCustomWidget);

Copilot uses AI. Check for mistakes.
```

Now use it in your schema:

```json
{
"type": "custom-widget",
"className": "my-custom-class",
"props": {
"customProp": "value"
}
}
```

**You're not limited to the built-in component set.** ObjectUI is a **rendering engine**, not a walled garden.

### Override Built-in Components

Don't like the default `Button` component? Replace it:

```typescript
import { registerRenderer } from '@object-ui/core';
import { MyCustomButton } from './components/MyCustomButton';

// Override the built-in button
registerRenderer('button', MyCustomButton);
Comment on lines +247 to +251
Copy link

Copilot AI Jan 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function registerRenderer does not exist in the @object-ui/core package. Based on the actual codebase, the correct API is either:

  1. ComponentRegistry.register() (imported from @object-ui/core)
  2. getComponentRegistry().register() (imported from @object-ui/react)

This inconsistency could confuse developers trying to use the documented API. Update to use the actual API that exists in the codebase.

Suggested change
import { registerRenderer } from '@object-ui/core';
import { MyCustomButton } from './components/MyCustomButton';
// Override the built-in button
registerRenderer('button', MyCustomButton);
import { ComponentRegistry } from '@object-ui/core';
import { MyCustomButton } from './components/MyCustomButton';
// Override the built-in button
ComponentRegistry.register('button', MyCustomButton);

Copilot uses AI. Check for mistakes.
```

All schemas using `"type": "button"` will now render **your** component.

### Mix with Existing React Code

ObjectUI components are **just React components**. Use them alongside your existing codebase:

```tsx
<div className="space-y-4 border p-4 rounded-lg">
<div className="flex flex-col gap-2 bg-slate-50">
<Label>Email Address</Label>
<Input name="email" />
</div>
</div>
function MyPage() {
return (
<div>
<MyExistingHeader />
<SchemaRenderer schema={formSchema} />
<MyExistingFooter />
</div>
);
}
```

**No migration required.** Adopt ObjectUI incrementally, one component at a time.

---

## Part of the ObjectStack Ecosystem

ObjectUI is the **official UI renderer** for the ObjectStack ecosystem, but it's **backend-agnostic** and works with any REST API.

### Standalone Usage

Connect ObjectUI to **any backend**:

- REST APIs (with the universal `DataSource` interface)
- GraphQL endpoints
- Firebase, Supabase, or custom backends
- Static JSON files for prototyping

### Perfect Pair with ObjectQL

For an **end-to-end protocol-driven experience**, pair ObjectUI with [**ObjectQL**](https://github.com/objectstack-ai/objectql):

- **ObjectQL** handles your backend: type-safe APIs from YAML schemas
- **ObjectUI** handles your frontend: beautiful UIs from JSON schemas

Together, they enable **full-stack development at configuration speed**—without sacrificing the control and quality of hand-written code.

**Learn more:** [ObjectQL Integration Guide](/integration/objectql)

---

## Ready to Build Faster?

Stop writing repetitive UI code. Start building with ObjectUI.

<div style="display: flex; gap: 1rem; margin-top: 2rem;">
<a href="/protocol/overview" style="padding: 0.75rem 1.5rem; background: #3b82f6; color: white; border-radius: 0.5rem; text-decoration: none; font-weight: 600;">Read the Spec</a>
<a href="/components/" style="padding: 0.75rem 1.5rem; border: 1px solid #3b82f6; color: #3b82f6; border-radius: 0.5rem; text-decoration: none; font-weight: 600;">View Component Gallery</a>
<a href="/guide/quick-start" style="padding: 0.75rem 1.5rem; border: 1px solid #6b7280; color: #6b7280; border-radius: 0.5rem; text-decoration: none; font-weight: 600;">Quick Start →</a>
</div>