Skip to main content

Theia IDE Integration Options

Avoiding the Iframe Wrapper

Current Production: Theia runs in iframe at /theia with React wrapper around it
Goal: Deep integration with unified studio UI


Use Theia's browser-only packages to compose your own IDE experience.

// Instead of iframe:
<iframe src="/theia" />

// Use Theia components directly:
import { FileNavigator } from '@theia/navigator/lib/browser';
import { MonacoEditor } from '@theia/monaco/lib/browser';
import { TerminalWidget } from '@theia/terminal/lib/browser';

function UnifiedStudio() {
return (
<div className="studio-layout">
<YourCustomSidebar>
<FileNavigator />
</YourCustomSidebar>

<YourCustomEditorArea>
<MonacoEditor />
</YourCustomEditorArea>

<YourCustomBottomPanel>
<TerminalWidget />
</YourCustomBottomPanel>
</div>
);
}

Pros

  • ✅ Full control over layout and styling
  • ✅ No iframe boundaries
  • ✅ Share state with rest of app
  • ✅ Custom chrome/tabs around Theia components
  • ✅ Seamless theme integration

Cons

  • ⚠️ Requires understanding Theia's DI container (Inversify)
  • ⚠️ Must wire up services manually
  • ⚠️ Breaking changes in Theia updates

Implementation

// lib/theia-container.ts
import { Container } from '@theia/core/shared/inversify';
import { createFileNavigatorContainer } from '@theia/navigator/lib/browser';
import { createMonacoEditorContainer } from '@theia/monaco/lib/browser';

export function createUnifiedStudioContainer() {
const container = new Container();

// Bind Theia services
container.load(createFileNavigatorContainer());
container.load(createMonacoEditorContainer());
container.load(createTerminalContainer());

// Bind your custom services
container.bind(YourCustomService).toSelf();

return container;
}

Option 2: Custom Theia Extension (What Production Currently Does)

Build a Theia extension that modifies the IDE from within.

// theia-app/src/browser/coditect-unified-module.ts
import { ContainerModule } from '@theia/core/shared/inversify';
import { ShellLayoutRestorer } from '@theia/core/lib/browser/shell/shell-layout-restorer';
import { CoditectShellLayoutRestorer } from './coditect-shell-layout';

export default new ContainerModule((bind, unbind, isBound, rebind) => {
// Replace Theia's default layout with unified studio layout
rebind(ShellLayoutRestorer).to(CoditectShellLayoutRestorer);

// Add custom title bar that communicates with parent
bind(CoditectTitleBar).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).toService(CoditectTitleBar);
});

How It Works

  1. Theia builds with your custom extension
  2. Your extension modifies the DOM to match unified studio
  3. Use postMessage to communicate with parent window
  4. Hide Theia's default chrome, replace with yours

Pros

  • ✅ Leverages Theia's full ecosystem
  • ✅ VS Code extensions still work
  • ✅ Can customize deeply

Cons

  • ⚠️ Still technically in Theia's world
  • ⚠️ Requires rebuilding Theia for changes
  • ⚠️ Complex build process

Option 3: Monaco + xterm.js Only (Lightweight)

Build custom IDE using just Monaco editor and xterm.js terminal.

// components/monaco-ide.tsx
import Editor from '@monaco-editor/react';
import { Terminal } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';

export function CustomIDE() {
return (
<div className="ide-layout">
<FileExplorer
onFileSelect={handleFileOpen}
files={fileSystem}
/>

<div className="editor-area">
{openFiles.map(file => (
<Tab key={file.path} active={file.path === activeFile}>
<Editor
path={file.path}
defaultValue={file.content}
language={file.language}
/>
</Tab>
))}
</div>

<Terminal
onData={handleTerminalInput}
ref={terminalRef}
/>
</div>
);
}

Pros

  • ✅ Lightweight (no Theia overhead)
  • ✅ Full control
  • ✅ Easy to customize
  • ✅ Fast load times

Cons

  • ⚠️ No VS Code extensions
  • ⚠️ Must implement debugging, git, etc. yourself
  • ⚠️ File system, search, etc. from scratch

Option 4: Reverse Proxy with Path Rewriting

Theia runs at root, unified studio overlays on top.

# nginx.conf
server {
listen 80;

# Theia IDE at /theia/*
location /theia/ {
proxy_pass http://theia:3000/;
proxy_set_header Host $host;
}

# Unified studio UI at /*
location / {
proxy_pass http://unified-studio:5173/;
}
}

Then use CSS to overlay unified studio chrome on Theia:

/* unified-studio-overlay.css */
.unified-header {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 40px;
z-index: 9999;
}

/* Push Theia down to make room for header */
.theia-app {
margin-top: 40px !important;
}

Pros

  • ✅ Theia runs natively
  • ✅ VS Code extensions work
  • ✅ Simple-ish setup

Cons

  • ⚠️ CSS hacks are fragile
  • ⚠️ Theia updates can break overlay
  • ⚠️ Two separate apps to maintain

Option 5: Theia "Browser-Only" Composition

Use Theia's new browser-only packages (experimental but promising).

// Import specific Theia packages
import { createFileService } from '@theia/filesystem/lib/browser/file-service';
import { createWorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
import { createEditorManager } from '@theia/editor/lib/browser/editor-manager';

// Compose your own IDE
const fileService = createFileService();
const workspaceService = createWorkspaceService();
const editorManager = createEditorManager();

function MyIDE() {
return (
<TheiaFileTree fileService={fileService} />
<TheiaEditorManager manager={editorManager} />
<TheiaTerminal service={terminalService} />
);
}

Recommendation: Hybrid Approach

Unified Studio Architecture (No Iframe)

├─ Core: Next.js 14 + Tailwind (you control this)
│ ├─ Unified Header (CODITECT branded)
│ ├─ Module Tabs (Dev Studio | IDE | AI Studio | ...)
│ └─ State Management (Zustand)

├─ Module: Dev Studio (custom, no Theia)
│ └─ Chat + Viz panels (already built)

├─ Module: Theia IDE (Option 1 - Library approach)
│ ├─ FileNavigator from '@theia/navigator'
│ ├─ MonacoEditor from '@theia/monaco'
│ ├─ TerminalWidget from '@theia/terminal'
│ └─ Your custom chrome around them

├─ Module: AI Studio (custom + Theia Chat)
│ ├─ Custom chat panel
│ └─ TheiaChatWidget from '@theia/ai-chat-ui'

└─ Module: Pitch Deck (pure custom)
└─ No Theia needed

Implementation Priority

Phase 1: Keep Iframe (Short Term)

  • Continue using iframe for Theia
  • Build unified chrome around it
  • Get to market faster

Phase 2: Component Extraction (Medium Term)

  • Extract Monaco editor as library
  • Extract terminal as library
  • File explorer from Theia or custom

Phase 3: Full Integration (Long Term)

  • Full Theia-as-library approach
  • Complete control over IDE experience
  • Share state across all modules

Code Example: Monaco Without Iframe

// components/editor/monaco-panel.tsx
'use client';

import Editor from '@monaco-editor/react';
import { useTheme } from 'next-themes';

interface MonacoPanelProps {
path: string;
content: string;
language?: string;
onChange?: (value: string) => void;
}

export function MonacoPanel({
path,
content,
language = 'typescript',
onChange
}: MonacoPanelProps) {
const { theme } = useTheme();

return (
<div className="h-full w-full rounded-lg overflow-hidden border">
<Editor
path={path}
defaultValue={content}
language={language}
theme={theme === 'dark' ? 'vs-dark' : 'light'}
onChange={onChange}
options={{
minimap: { enabled: true },
fontSize: 14,
lineNumbers: 'on',
roundedSelection: false,
scrollBeyondLastLine: false,
readOnly: false,
automaticLayout: true,
}}
/>
</div>
);
}

Decision Matrix

ApproachEffortFlexibilityVS Code ExtProduction Ready
Iframe (current)LowLow
Theia as LibraryHighHigh⚠️
Custom Theia ExtMediumMedium
Monaco + xtermMediumVery High
Reverse ProxyLowLow⚠️

My Recommendation

For immediate needs: Keep iframe, build unified chrome around it.
For 6-month horizon: Migrate to Monaco + xterm.js for Dev Studio module.
For IDE module: Keep Theia iframe OR invest in Theia-as-library.

The Monaco + xterm.js approach gives you the best balance of control and effort for a unified studio that feels cohesive.