Skip to Content
Config SystemEditor Placements

Editor Placements

Placements embed custom UI into the Foir editor. You can add a full-page editor tab or a sidebar panel that loads your own web application inside an iframe.

Placement Interface

interface ApplyConfigPlacementInput { type: string; // Placement type: 'main-editor' or 'sidebar' url: string; // URL of your custom UI allowedOrigin?: string; // Origin allowed for postMessage communication height?: number; // Height of the iframe in pixels tabName?: string; // Tab label in the editor hideContentTab?: boolean; // Hide the default content editing tab modelKeys?: string[]; // Restrict placement to specific models }

Placement Types

main-editor

Adds a tab to the main editor area. When users open a record of a matching model, they see your custom tab alongside (or instead of) the default content tab.

placements: [ { type: 'main-editor', url: '/', modelKeys: ['redirect'], tabName: 'Redirect Editor', hideContentTab: true, }, ]

Adds a panel in the editor sidebar. Sidebar placements appear alongside the built-in sidebar sections.

placements: [ { type: 'sidebar', url: '/sidebar', modelKeys: ['blog-post'], tabName: 'SEO Tools', height: 400, }, ]

Options

url

The URL loaded in the iframe. This can be a relative path (resolved against your service’s base URL) or an absolute URL.

// Relative -- resolved at push time { type: 'main-editor', url: '/' } // Absolute -- used as-is { type: 'main-editor', url: 'https://my-editor.example.com' }

modelKeys

Restricts the placement to specific models. If omitted, the placement appears for all models.

// Only show for redirect and vanity-url models { type: 'main-editor', url: '/', modelKeys: ['redirect', 'vanity-url'] }

hideContentTab

When true, the default content editing tab is hidden. Use this when your custom editor completely replaces the built-in editor.

// Replace the default editor entirely { type: 'main-editor', url: '/', modelKeys: ['design-system'], hideContentTab: true, tabName: 'Design Tokens', }

tabName

The label shown on the editor tab. Defaults to the config name if not specified.

height

Sets the iframe height in pixels. Mainly useful for sidebar placements where you want to control the panel size.

{ type: 'sidebar', url: '/preview', height: 300 }

allowedOrigin

The origin allowed for postMessage communication between the editor and your iframe. Set this to enable two-way communication with the Foir editor SDK.

{ type: 'main-editor', url: 'https://my-editor.example.com', allowedOrigin: 'https://my-editor.example.com', }

Examples

Custom Main Editor

Replace the default editor with a custom redirect management UI:

import { defineConfig } from '@eide/foir-cli/configs'; export default defineConfig({ key: 'cloudflare-kv', name: 'Cloudflare KV Redirector', models: [ { key: 'redirect', name: 'Redirect', fields: [...] }, ], placements: [ { type: 'main-editor', url: '/', modelKeys: ['redirect'], hideContentTab: true, tabName: 'Redirect Editor', }, ], });

Design Token Editor

A custom editor for design system tokens with an external URL and allowed origin:

placements: [ { type: 'main-editor', url: 'https://design-editor.example.com', allowedOrigin: 'https://design-editor.example.com', tabName: 'Design Tokens', hideContentTab: true, modelKeys: ['design-system'], }, ]

Add a sidebar panel that shows a live preview of content:

placements: [ { type: 'sidebar', url: '/preview', modelKeys: ['page', 'blog-post'], tabName: 'Live Preview', height: 500, }, ]

Multiple Placements

You can define multiple placements in the same config:

placements: [ { type: 'main-editor', url: '/', modelKeys: ['product'], tabName: 'Product Editor', }, { type: 'sidebar', url: '/analytics', modelKeys: ['product'], tabName: 'Analytics', height: 350, }, ]

Next Steps

Last updated on