ObjectUIObjectUI

Plugins

Object UI supports a powerful plugin system that allows you to extend the framework with additional components. Plugins are separate packages that load on-demand, keeping your main application bundle small while providing rich functionality.

Overview

Plugins are lazy-loaded component packages that:

  • Auto-register components when imported
  • Lazy-load heavy dependencies on-demand
  • Keep bundles small - only load when needed
  • Are type-safe with full TypeScript support
  • Follow best practices with built-in loading states

Official Plugins

Object UI provides 14+ official plugins for common use cases:

Data Visualization & Dashboards

@object-ui/plugin-charts

Data visualization components powered by Recharts.

  • Bar, line, area, and pie charts
  • Responsive design
  • Customizable colors
  • Lazy-loaded (~80 KB)

Read full documentation →


@object-ui/plugin-dashboard

Dashboard layouts with metric cards and widgets.

  • Dashboard grid layouts
  • Metric/KPI cards with trends
  • Widget system
  • Lazy-loaded (~22 KB)

Read full documentation →


@object-ui/plugin-timeline

Timeline component with multiple layout variants.

  • Vertical, horizontal layouts
  • Customizable markers
  • Date formatting
  • Lazy-loaded (~20 KB)

Read full documentation →


@object-ui/plugin-gantt

Gantt chart for project visualization.

  • Task dependencies
  • Progress tracking
  • ObjectQL integration
  • Lazy-loaded (~40 KB)

Read full documentation →


@object-ui/plugin-calendar

Calendar visualization for events.

  • Month/week/day views
  • Event management
  • ObjectQL integration
  • Lazy-loaded (~25 KB)

Read full documentation →


@object-ui/plugin-map

Map visualization with markers.

  • Interactive maps
  • Location markers
  • ObjectQL integration
  • Lazy-loaded (~60 KB)

Read full documentation →


Data Management

@object-ui/plugin-grid

Advanced data grid with sorting, filtering, and pagination.

  • Column sorting and filtering
  • Pagination controls
  • Row selection
  • Lazy-loaded (~45 KB)

Read full documentation →


@object-ui/plugin-aggrid

Enterprise data grid powered by AG Grid.

  • Advanced filtering
  • Row editing
  • Multiple themes
  • Lazy-loaded (~150 KB)

Read full documentation →


@object-ui/plugin-form

Advanced form builder with validation.

  • Multi-step forms
  • Field validation
  • Custom field types
  • Lazy-loaded (~28 KB)

Read full documentation →


@object-ui/plugin-view

ObjectQL-integrated views for automatic CRUD.

  • Auto-generated forms and grids
  • CRUD operations
  • Field mapping
  • Lazy-loaded (~35 KB)

Read full documentation →


Content & Editing

@object-ui/plugin-editor

Code editor component powered by Monaco Editor.

  • Syntax highlighting for 100+ languages
  • IntelliSense and code completion
  • Multiple themes
  • Lazy-loaded (~120 KB)

Read full documentation →


@object-ui/plugin-markdown

Markdown renderer with GitHub Flavored Markdown support.

  • GitHub Flavored Markdown
  • XSS protection
  • Code syntax highlighting
  • Lazy-loaded (~30 KB)

Read full documentation →


@object-ui/plugin-chatbot

Chat interface component.

  • Message history
  • User and assistant roles
  • Timestamps and avatars
  • Lazy-loaded (~35 KB)

Read full documentation →


Workflows & Tasks

@object-ui/plugin-kanban

Kanban board component with drag-and-drop powered by @dnd-kit.

  • Drag and drop cards between columns
  • Column limits (WIP limits)
  • Card badges for status/priority
  • Lazy-loaded (~100 KB)

Read full documentation →


How Plugins Work

Lazy Loading Architecture

Plugins use React's lazy() and Suspense to load heavy dependencies on-demand:

// The plugin structure
import React, { Suspense } from 'react'
import { Skeleton } from '@object-ui/components'

// Lazy load the heavy implementation
const LazyEditor = React.lazy(() => import('./MonacoImpl'))

export const CodeEditorRenderer = (props) => (
  <Suspense fallback={<Skeleton className="w-full h-[400px]" />}>
    <LazyEditor {...props} />
  </Suspense>
)

Benefits:

  • Smaller initial bundle: Main app loads faster
  • Progressive loading: Components load when needed
  • Better UX: Loading skeletons while chunks download
  • Automatic code splitting: Vite handles chunking

Bundle Impact

PluginInitial LoadLazy LoadDescription
plugin-editor~0.2 KB~120 KBMonaco editor
plugin-charts~0.2 KB~80 KBRecharts visualization
plugin-kanban~0.2 KB~100 KBDrag-and-drop board
plugin-markdown~0.2 KB~30 KBMarkdown rendering
plugin-aggrid~0.2 KB~150 KBAG Grid data grid
plugin-dashboard~0.2 KB~22 KBDashboard layouts
plugin-form~0.2 KB~28 KBForm builder
plugin-grid~0.2 KB~45 KBData grid
plugin-view~0.2 KB~35 KBObjectQL views
plugin-timeline~0.2 KB~20 KBTimeline layouts
plugin-chatbot~0.2 KB~35 KBChat interface
plugin-calendar~0.2 KB~25 KBCalendar views
plugin-gantt~0.2 KB~40 KBGantt charts
plugin-map~0.2 KB~60 KBMap visualization

Without lazy loading, all this code would be in your main bundle!

Auto-Registration

Plugins automatically register their components when imported:

// In the plugin's index.tsx
import { ComponentRegistry } from '@object-ui/core'

ComponentRegistry.register('code-editor', CodeEditorRenderer)

You just need to import the plugin once:

// In your App.tsx or main.tsx
import '@object-ui/plugin-editor'
import '@object-ui/plugin-charts'
import '@object-ui/plugin-kanban'
import '@object-ui/plugin-markdown'
import '@object-ui/plugin-dashboard'
import '@object-ui/plugin-form'
import '@object-ui/plugin-grid'
// ... import other plugins as needed

Now all plugin components are available in your schemas!

Creating Custom Plugins

You can create your own plugins following the same pattern:

1. Create Package Structure

mkdir -p packages/plugin-myfeature/src
cd packages/plugin-myfeature

2. Create Heavy Implementation

// src/MyFeatureImpl.tsx
import HeavyLibrary from 'heavy-library'

export default function MyFeatureImpl(props) {
  return <HeavyLibrary {...props} />
}

3. Create Lazy Wrapper

// src/index.tsx
import React, { Suspense } from 'react'
import { ComponentRegistry } from '@object-ui/core'
import { Skeleton } from '@object-ui/components'

// Lazy load implementation
const LazyFeature = React.lazy(() => import('./MyFeatureImpl'))

// Create renderer with Suspense
export const MyFeatureRenderer = (props) => (
  <Suspense fallback={<Skeleton className="w-full h-[300px]" />}>
    <LazyFeature {...props} />
  </Suspense>
)

// Auto-register
ComponentRegistry.register('my-feature', MyFeatureRenderer)

// Export for manual use
export const myFeatureComponents = {
  'my-feature': MyFeatureRenderer
}

4. Add TypeScript Types

// src/types.ts
import type { BaseSchema } from '@object-ui/types'

export interface MyFeatureSchema extends BaseSchema {
  type: 'my-feature'
  customProp?: string
}

5. Configure Build

// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'

export default defineConfig({
  plugins: [react()],
  build: {
    lib: {
      entry: resolve(__dirname, 'src/index.tsx'),
      name: 'ObjectUIPluginMyFeature',
      fileName: (format) => `index.${format}.js`
    },
    rollupOptions: {
      external: [
        'react',
        'react-dom',
        '@object-ui/components',
        '@object-ui/core'
      ],
      output: {
        globals: {
          react: 'React',
          'react-dom': 'ReactDOM'
        }
      }
    }
  }
})

6. Add Package.json

{
  "name": "@object-ui/plugin-myfeature",
  "version": "1.0.0",
  "type": "module",
  "main": "./dist/index.umd.js",
  "module": "./dist/index.es.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.es.js",
      "require": "./dist/index.umd.js",
      "types": "./dist/index.d.ts"
    }
  },
  "files": ["dist"],
  "scripts": {
    "build": "vite build && tsc --emitDeclarationOnly"
  },
  "peerDependencies": {
    "react": "^18.0.0 || ^19.0.0",
    "react-dom": "^18.0.0 || ^19.0.0"
  },
  "dependencies": {
    "heavy-library": "^1.0.0"
  },
  "devDependencies": {
    "@object-ui/components": "workspace:*",
    "@object-ui/core": "workspace:*",
    "@object-ui/types": "workspace:*",
    "typescript": "^5.0.0",
    "vite": "^5.0.0"
  }
}

Best Practices

1. Keep Entry Point Light

The main index file should only contain:

  • Lazy loading wrapper
  • Component registration
  • Type exports

Heavy imports go in the *Impl.tsx file.

2. Provide Good Loading States

Always show a meaningful skeleton while loading:

<Suspense fallback={
  <Skeleton className="w-full h-[400px]" />
}>
  <LazyComponent {...props} />
</Suspense>

3. Export Types

Make your plugin type-safe:

export type { MyFeatureSchema } from './types'

4. Document Your Plugin

Include a README with:

  • Installation instructions
  • Usage examples
  • Schema API reference
  • Bundle size information

5. Test Lazy Loading

Verify that:

  • The main bundle is small (~200 bytes)
  • The lazy chunk is separate
  • Components load correctly when rendered
pnpm build
ls -lh dist/

Plugin vs Component Package

Use a Plugin when:

  • The component depends on large libraries (>50 KB)
  • Not all apps will use this component
  • You want on-demand loading

Use regular Components when:

  • The component is lightweight
  • Most apps will use it
  • It's part of core functionality

Troubleshooting

Plugin not loading

Check that you imported it in your app:

import '@object-ui/plugin-myfeature'

TypeScript errors

Make sure types are exported:

export type { MyFeatureSchema } from '@object-ui/plugin-myfeature'

Bundle size too large

Check that the implementation is in a separate file:

✅ src/index.tsx        (light, uses React.lazy)
✅ src/MyFeatureImpl.tsx (heavy, imported lazily)

Component not registering

Check that ComponentRegistry.register() is called at the module level:

// ✅ Good - runs on import
ComponentRegistry.register('my-feature', MyFeatureRenderer)

// ❌ Bad - never runs
export function registerComponents() {
  ComponentRegistry.register('my-feature', MyFeatureRenderer)
}

Next Steps

  1. Install official plugins you need
  2. Try creating a custom plugin
  3. Share your plugins with the community
  4. Contribute new plugins to Object UI

On this page