
Thatopen Syntax Ui
- 5 installs
- 17 repo stars
- Updated July 8, 2026
- openaec-foundation/thatopen-claude-skill-package
Helps with ai & agent building tasks.
About
thatopen-syntax-ui is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- thatopen-syntax-ui
- AI & Agent Building
- AI-coding skill
Thatopen Syntax Ui by the numbers
- 5 all-time installs (skills.sh)
- Ranked #13,052 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Jul 21, 2026 (Skillselion catalog sync)
npx skills add https://github.com/openaec-foundation/thatopen-claude-skill-package --skill thatopen-syntax-uiAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 5 |
|---|---|
| repo stars | ★ 17 |
| Last updated | July 8, 2026 |
| Repository | openaec-foundation/thatopen-claude-skill-package ↗ |
What it does
Helps with ai & agent building tasks.
Files
ThatOpen UI Component Syntax
Purpose
This skill covers the syntax and usage patterns for ThatOpen's UI component library (@thatopen/ui) and its BIM-connected counterpart (@thatopen/ui-obc). It provides component catalogs, property references, layout patterns, CSS theming, and event handling. For underlying Lit web component patterns, see lit-bim-ui.
Version: @thatopen/ui 3.3.x / @thatopen/ui-obc 3.3.x
Mandatory Initialization
ALWAYS call BUI.Manager.init() before using ANY bim-* element in your application. This registers all custom elements and injects global styles.
import * as BUI from "@thatopen/ui";
// ALWAYS call this once at application startup
BUI.Manager.init();Without this call, bim-* tags render as unknown HTML elements with no styling or behavior. The browser silently ignores unregistered custom elements.
Manager API
class Manager {
// Register all bim-* custom elements and inject global styles
static init(
querySelectorElements?: string, // optional CSS selector for animation targets
animateOnLoad?: boolean // default: true — entrance animations
): void;
// Switch between dark and light theme
static toggleTheme(animate?: boolean): void;
// Preload icon collections (Iconify)
static preloadIcons(collections: string[], log?: boolean): Promise<void>;
// Configuration
static config: ManagerConfig;
}
interface ManagerConfig {
sectionLabelOnVerticalToolbar: boolean; // default: false
internalComponentNameAttribute: string;
}Package Architecture
| Package | Role | Dependencies |
|---|---|---|
@thatopen/ui | Presentational web components | Standalone (Lit-based) |
@thatopen/ui-obc | Functional BIM components | @thatopen/ui + @thatopen/components |
@thatopen/ui provides generic UI elements (panels, toolbars, tables, inputs). These have NO dependency on the ThatOpen engine — they work as standalone web components in any HTML page.
@thatopen/ui-obc provides pre-wired BIM components that connect UI elements to @thatopen/components engine functionality (model trees, property tables, IFC load buttons). These ALWAYS require a Components instance.
Core Component Catalog
All components use the bim- prefix and are registered by BUI.Manager.init().
Layout Components
| Element | Description | Key Properties |
|---|---|---|
bim-grid | CSS Grid layout container | layout, layouts, floating, resizeableAreas |
bim-panel | Collapsible side panel | name, label, icon, hidden, headerHidden |
bim-panel-section | Section within a panel | label, icon, collapsed, fixed |
bim-toolbar | Horizontal/vertical toolbar | vertical, labelsHidden, hidden |
bim-toolbar-section | Group within a toolbar | label, icon, vertical |
bim-toolbar-group | Nested button group | vertical |
bim-viewport | 3D rendering container | Wraps canvas for renderer |
bim-tabs | Tab container | Active tab management |
bim-tab | Individual tab | label, icon |
Interactive Components
| Element | Description | Key Properties |
|---|---|---|
bim-button | Action button | label, icon, disabled, active, vertical |
bim-checkbox | Boolean toggle | label, checked, inverted |
bim-text-input | Text entry | label, value, placeholder |
bim-number-input | Numeric entry | label, value, min, max, step, suffix |
bim-color-input | Color picker | label, color, opacity |
bim-dropdown | Select menu | label, multiple, required |
bim-option | Dropdown option | label, value, checked, icon |
bim-selector | Radio-style selector | label, multiple |
Display Components
| Element | Description | Key Properties |
|---|---|---|
bim-label | Text with optional icon | icon, img |
bim-icon | Iconify icon display | icon |
bim-table | Data table with hierarchy | data, columns, expanded, selectableRows |
bim-chart | Chart visualization | Chart data binding |
bim-tooltip | Hover tooltip | Text content |
bim-context-menu | Right-click menu | Menu items |
Grid Layout System
The bim-grid component provides CSS Grid-based layouts with named areas. This is the PRIMARY way to compose a full BIM application layout.
const grid = document.createElement("bim-grid");
// Define named layouts
grid.layouts = {
main: {
template: `
"toolbar toolbar" auto
"panel viewport" 1fr
/ 320px 1fr
`,
elements: {
toolbar: toolbarElement,
panel: panelElement,
viewport: viewportElement,
},
},
fullscreen: {
template: `"viewport" 1fr / 1fr`,
elements: { viewport: viewportElement },
},
};
// Activate a layout
grid.layout = "main";Layout Template Syntax
The template string maps directly to CSS grid-template. Format:
"area1 area2" rowSize
"area3 area4" rowSize
/ col1Size col2SizeResizable Areas
Enable user-resizable grid tracks:
grid.resizeableAreas = true;
// Optionally exclude areas from resizing
grid.areasResizeExceptions = ["toolbar"];bim-panel Pattern
Panels contain sections. Sections contain form elements or custom content.
<bim-panel name="Properties" icon="settings">
<bim-panel-section label="General" icon="info" fixed>
<bim-text-input label="Name" value="Wall-001"></bim-text-input>
<bim-number-input label="Height" value="3.0" suffix="m"></bim-number-input>
<bim-checkbox label="Structural" checked></bim-checkbox>
</bim-panel-section>
<bim-panel-section label="Materials" icon="palette" collapsed>
<bim-color-input label="Color" color="#ff6600"></bim-color-input>
<bim-dropdown label="Material">
<bim-option label="Concrete" checked></bim-option>
<bim-option label="Steel"></bim-option>
<bim-option label="Wood"></bim-option>
</bim-dropdown>
</bim-panel-section>
</bim-panel>Panel Value Collection
The panel aggregates values from its child form elements:
const panel = document.querySelector("bim-panel");
panel.addEventListener("change", () => {
const values = panel.value;
// { "Name": "Wall-001", "Height": 3.0, "Structural": true, ... }
});Panel Activation Button
Every panel creates an activationButton that toggles its visibility:
const panel = document.querySelector("bim-panel");
const toggleBtn = panel.activationButton;
// Place this button in a toolbar to show/hide the panel
toolbar.appendChild(toggleBtn);bim-toolbar Pattern
Toolbars group buttons into sections. Sections can nest toolbar-groups.
<bim-toolbar>
<bim-toolbar-section label="Navigation">
<bim-button icon="open_with" label="Orbit"
@click=${() => camera.set("Orbit")}></bim-button>
<bim-button icon="visibility" label="First Person"
@click=${() => camera.set("FirstPerson")}></bim-button>
</bim-toolbar-section>
<bim-toolbar-section label="Tools">
<bim-toolbar-group>
<bim-button icon="straighten" label="Measure"></bim-button>
<bim-button icon="content_cut" label="Clip"></bim-button>
</bim-toolbar-group>
</bim-toolbar-section>
</bim-toolbar>Vertical Toolbar
<bim-toolbar vertical>
<!-- labelsHidden is auto-set when vertical=true -->
<bim-toolbar-section label="Tools">
<bim-button icon="select_all" label="Select"></bim-button>
</bim-toolbar-section>
</bim-toolbar>When vertical=true, section labels are hidden by default. Override with:
BUI.Manager.config.sectionLabelOnVerticalToolbar = true;bim-table Pattern
Tables display hierarchical data with filtering, grouping, and selection.
const table = document.createElement("bim-table");
table.columns = [
{ name: "Name", width: "minmax(200px, 1fr)" },
{ name: "Type", width: "120px" },
{ name: "Level", width: "100px" },
];
table.data = [
{
data: { Name: "Wall-001", Type: "IfcWall", Level: "Level 1" },
children: [
{ data: { Name: "Opening-001", Type: "IfcOpeningElement", Level: "Level 1" } },
],
},
{
data: { Name: "Slab-001", Type: "IfcSlab", Level: "Level 1" },
},
];
// Enable row selection
table.selectableRows = true;
table.addEventListener("dataselected", (e) => {
const row = e.detail.data;
});Table Filtering
// Simple text search
table.queryString = "wall";
// Column-specific query
table.queryString = 'Type="IfcWall" & Level="Level 1"';Table Export
table.downloadData("export", "csv"); // or "tsv"CSS Theming System
All bim-* components use CSS custom properties with the --bim-ui_ prefix. Override at any level in the DOM tree. Key variable groups:
- Backgrounds:
--bim-ui_bg-base,--bim-ui_bg-contrast-{10,20,40,60,80,100} - Accent:
--bim-ui_accent-base,--bim-ui_accent-contrast - Sizing:
--bim-ui_size-{base,2xs,xs,sm,md,lg,xl} - Typography:
--bim-ui_font-family
See references/methods.md for full variable list with defaults.
:root {
--bim-ui_bg-base: #0d1117;
--bim-ui_accent-base: #238636;
--bim-ui_font-family: "JetBrains Mono", monospace;
}Theme Switching
BUI.Manager.toggleTheme(); // instant switch
BUI.Manager.toggleTheme(true); // animated overlay transitionThis toggles bim-ui-dark / bim-ui-light CSS classes on the <html> element.
Event Handling
All bim-* components dispatch standard DOM events. Use @event syntax in Lit templates or addEventListener in vanilla JS.
Common Events
| Component | Event | Detail |
|---|---|---|
bim-button | click | Standard MouseEvent |
bim-checkbox | change | { checked: boolean } |
bim-text-input | input | { value: string } |
bim-number-input | change | { value: number } |
bim-color-input | change | { color: string, opacity: number } |
bim-dropdown | change | Selected options |
bim-panel | change | Aggregated form values |
bim-panel | hiddenchange | Hidden state toggled |
bim-toolbar | hiddenchange | Hidden state toggled |
bim-table | dataselected | { data: row } |
bim-table | datadeselected | { data: row } |
bim-grid | layoutchange | Layout name changed |
Vanilla JS Event Handling
const btn = document.querySelector("bim-button");
btn.addEventListener("click", () => {
console.log("Button clicked");
});
const checkbox = document.querySelector("bim-checkbox");
checkbox.addEventListener("change", (e) => {
console.log("Checked:", checkbox.checked);
});@thatopen/ui-obc: Functional BIM Components
These are pre-built UI component factories that wire @thatopen/ui elements to @thatopen/components engine functionality. ALWAYS import from @thatopen/ui-obc separately.
import * as BUI from "@thatopen/ui";
import * as OBC from "@thatopen/components";
import * as OBCF from "@thatopen/components-front";
import * as CUI from "@thatopen/ui-obc";
BUI.Manager.init();Available Functional Components
| Category | Components | Description |
|---|---|---|
| Buttons | loadIfc, loadFrag | IFC/Fragment file load buttons |
| Tables | spatialTree, itemsData, modelsList | Model data tables |
| Tables | viewpointsList, topicsList, commentsList | BCF data tables |
| Sections | topicComments, topicInformation | BCF topic panels |
| Sections | topicRelations, topicViewpoints | BCF relation panels |
| Forms | Form builders | Configuration forms |
| Charts | Chart builders | Data visualization |
Usage Pattern
ui-obc components are factory functions that return configured HTML elements:
// Create a spatial tree table wired to the engine
const [tree, updateTree] = CUI.tables.spatialTree({
components,
models: [],
});
// Create IFC load button
const [loadBtn, updateLoadBtn] = CUI.buttons.loadIfc({ components });
// Append to DOM
panel.appendChild(tree);
toolbar.appendChild(loadBtn);The factory pattern returns a tuple: [element, updateFunction]. Call the update function when engine state changes to refresh the UI.
Slot-Based Composition
ThatOpen UI uses the Web Components slot system. Parent components define slots; child components fill them. ALWAYS nest components correctly:
| Parent | Accepts (default slot) |
|---|---|
bim-panel | bim-panel-section |
bim-panel-section | Any form elements or content |
bim-toolbar | bim-toolbar-section |
bim-toolbar-section | bim-button, bim-toolbar-group |
bim-toolbar-group | bim-button |
bim-dropdown | bim-option |
bim-selector | bim-option |
bim-tabs | bim-tab |
Complete BIM Application Layout
See references/examples.md E-001 for the full implementation. The essential pattern:
BUI.Manager.init();
// ... engine setup, create world ...
const viewport = document.createElement("bim-viewport");
// ... renderer uses viewport as container ...
const grid = document.createElement("bim-grid");
grid.layouts = {
main: {
template: `"toolbar toolbar" auto "panel viewport" 1fr / 320px 1fr`,
elements: { toolbar, panel, viewport },
},
};
grid.layout = "main";
document.body.appendChild(grid);Critical Rules
1. ALWAYS call BUI.Manager.init() before using any bim-* element. 2. ALWAYS use the bim- prefix for element tag names — these are the registered custom element names. NEVER use unprefixed names. 3. ALWAYS set grid.layouts before setting grid.layout — the layout name must exist in the layouts object. 4. ALWAYS import @thatopen/ui-obc separately from @thatopen/ui — they are different packages with different dependencies. 5. NEVER use bim-* elements without BUI.Manager.init() — they will render as empty unknown elements with no functionality. 6. NEVER set properties on bim-* elements before they are defined — call Manager.init() first or wait for customElements.whenDefined(). 7. NEVER style bim-* internals directly — use CSS custom properties (--bim-ui_*) for theming. Shadow DOM encapsulates internal styles.
Reference Files
- references/methods.md — BUI.Manager API, complete
component property catalog, CSS custom properties
- references/examples.md — Panel layout, toolbar,
table, property panel, and grid examples
- references/anti-patterns.md — Missing init,
wrong element names, direct style manipulation
Source Verification
All API signatures verified against:
- GitHub:
ThatOpen/engine_ui-componentsmain branch (packages/core/src/) - npm:
@thatopen/ui@3.3.3,@thatopen/ui-obc@3.3.3 - Research:
docs/research/vooronderzoek-thatopen.md(Section 8)
Anti-Patterns — UI Component Syntax
Version: @thatopen/ui 3.3.x / @thatopen/ui-obc 3.3.x
Common mistakes when using ThatOpen UI components — and what to do instead.
---
AP-001: Missing BUI.Manager.init()
WRONG:
import * as BUI from "@thatopen/ui";
// Immediately create bim-* elements without init
const panel = document.createElement("bim-panel");
panel.name = "Properties";
document.body.appendChild(panel);
// Result: <bim-panel> renders as unknown element — no styling, no behaviorCORRECT:
import * as BUI from "@thatopen/ui";
// ALWAYS call init() before any bim-* element usage
BUI.Manager.init();
const panel = document.createElement("bim-panel");
panel.name = "Properties";
document.body.appendChild(panel);Why: BUI.Manager.init() registers all bim-* custom elements with the browser's Custom Elements Registry and injects global styles. Without it, the browser treats bim-* tags as generic HTMLElement instances — they render empty with no Shadow DOM, no styles, and no reactive properties. The failure is silent: no errors appear in the console.
---
AP-002: Wrong Element Tag Names
WRONG:
// These element names do NOT exist in @thatopen/ui
const panel = document.createElement("bim-side-panel"); // wrong
const section = document.createElement("bim-section"); // wrong
const input = document.createElement("bim-input-text"); // wrong
const group = document.createElement("bim-button-group"); // wrongCORRECT:
// Use the EXACT registered element names
const panel = document.createElement("bim-panel");
const section = document.createElement("bim-panel-section");
const input = document.createElement("bim-text-input");
const group = document.createElement("bim-toolbar-group");Why: Custom elements MUST match the exact tag name registered by BUI.Manager.init(). Misspelled or invented names create generic HTML elements with no functionality. There is no fuzzy matching or helpful error message — the browser silently creates an unknown element.
Complete Tag Name Reference
| Correct Name | Common Mistakes |
|---|---|
bim-panel | bim-side-panel, bim-sidebar |
bim-panel-section | bim-section, bim-panel-group |
bim-toolbar | bim-menubar, bim-actionbar |
bim-toolbar-section | bim-toolbar-group (this is a different element) |
bim-toolbar-group | bim-button-group, bim-group |
bim-text-input | bim-input-text, bim-input, bim-textfield |
bim-number-input | bim-input-number, bim-numeric-input |
bim-color-input | bim-input-color, bim-colorpicker |
bim-dropdown | bim-select, bim-combobox |
bim-checkbox | bim-toggle, bim-switch |
---
AP-003: Setting Grid Layout Before Defining Layouts
WRONG:
const grid = document.createElement("bim-grid");
// Setting layout name before layouts are defined — logs warning, nothing renders
grid.layout = "main";
grid.layouts = {
main: {
template: `"viewport" 1fr / 1fr`,
elements: { viewport },
},
};CORRECT:
const grid = document.createElement("bim-grid");
// ALWAYS define layouts first
grid.layouts = {
main: {
template: `"viewport" 1fr / 1fr`,
elements: { viewport },
},
};
// THEN activate
grid.layout = "main";Why: When layout is set, the Grid component looks up the name in its layouts collection. If the collection is empty or the name does not exist, it logs a warning and renders nothing. The layout name MUST exist in the layouts object at the time it is assigned.
---
AP-004: Directly Styling Shadow DOM Internals
WRONG:
/* These selectors CANNOT pierce Shadow DOM */
bim-panel .header { background: red; }
bim-button span { color: blue; }
bim-toolbar > div { gap: 10px; }CORRECT:
/* Use CSS custom properties — they DO cross Shadow DOM boundaries */
bim-panel {
--bim-ui_bg-base: #1e293b;
--bim-ui_bg-contrast-80: #e2e8f0;
}
bim-button {
--bim-ui_accent-base: #3b82f6;
}Why: bim-* components use Shadow DOM for style encapsulation. External CSS selectors cannot target elements inside the Shadow Root. CSS custom properties are the ONLY way to theme these components from outside, because custom properties inherit through Shadow DOM boundaries by design.
---
AP-005: Using bim-* Elements in HTML Without init()
WRONG:
<!-- In static HTML without any JavaScript initialization -->
<bim-grid layout="main">
<bim-toolbar>
<bim-toolbar-section label="File">
<bim-button label="Open" icon="folder"></bim-button>
</bim-toolbar-section>
</bim-toolbar>
</bim-grid>CORRECT:
<bim-grid layout="main">
<bim-toolbar>
<bim-toolbar-section label="File">
<bim-button label="Open" icon="folder"></bim-button>
</bim-toolbar-section>
</bim-toolbar>
</bim-grid>
<script type="module">
import * as BUI from "@thatopen/ui";
// ALWAYS init — even when using declarative HTML
BUI.Manager.init();
</script>Why: HTML custom element tags are parsed by the browser but remain unresolved until their constructors are registered via customElements.define(). BUI.Manager.init() calls customElements.define() for every bim-* element. Without the script, all elements exist in the DOM as undefined custom elements with no rendering behavior.
---
AP-006: Mixing Up @thatopen/ui and @thatopen/ui-obc
WRONG:
import * as BUI from "@thatopen/ui";
// ui-obc components are NOT part of @thatopen/ui
const [tree, update] = BUI.tables.spatialTree({ components }); // ERROR
const [btn, updateBtn] = BUI.buttons.loadIfc({ components }); // ERRORCORRECT:
import * as BUI from "@thatopen/ui";
import * as CUI from "@thatopen/ui-obc";
BUI.Manager.init();
// Functional BIM components come from ui-obc
const [tree, updateTree] = CUI.tables.spatialTree({ components, models: [] });
const [btn, updateBtn] = CUI.buttons.loadIfc({ components });Why: @thatopen/ui provides presentational web components with no engine dependency. @thatopen/ui-obc provides functional BIM components that require @thatopen/components. They are separate packages with different imports. Attempting to access ui-obc APIs from the ui import results in TypeError: Cannot read properties of undefined.
---
AP-007: Forgetting to Call the Update Function (ui-obc)
WRONG:
const [tree, updateTree] = CUI.tables.spatialTree({ components, models: [] });
// Model loaded but tree is never updated — still shows empty
fragments.onFragmentsLoaded.add((model) => {
// Missing updateTree call
});CORRECT:
const [tree, updateTree] = CUI.tables.spatialTree({ components, models: [] });
fragments.onFragmentsLoaded.add((model) => {
// ALWAYS call the update function with new data
updateTree({ models: [model] });
});Why: ui-obc factory functions return [element, updateFunction]. The element is created once with the initial config. When engine state changes (new model loaded, selection changed), you MUST call the update function to re-render the component with new data. The component does NOT automatically observe engine state changes.
---
AP-008: Nesting Components in Wrong Parents
WRONG:
<!-- bim-option directly in body — must be inside dropdown or selector -->
<bim-option label="Concrete"></bim-option>
<!-- bim-panel-section outside a panel — loses form value aggregation -->
<div>
<bim-panel-section label="Settings">
<bim-text-input label="Name"></bim-text-input>
</bim-panel-section>
</div>
<!-- bim-toolbar-section outside toolbar — loses vertical/label propagation -->
<div>
<bim-toolbar-section label="Tools">
<bim-button label="Measure"></bim-button>
</bim-toolbar-section>
</div>CORRECT:
<bim-dropdown label="Material">
<bim-option label="Concrete"></bim-option>
</bim-dropdown>
<bim-panel name="Settings">
<bim-panel-section label="General">
<bim-text-input label="Name"></bim-text-input>
</bim-panel-section>
</bim-panel>
<bim-toolbar>
<bim-toolbar-section label="Tools">
<bim-button label="Measure"></bim-button>
</bim-toolbar-section>
</bim-toolbar>Why: ThatOpen UI components use slot-based composition. Parent components propagate properties to children via slotchange events (e.g., toolbar sets vertical and labelsHidden on its sections). Panels aggregate form values from their sections. Placing child components outside their expected parent breaks property propagation and event bubbling.
---
AP-009: Setting Properties Before Custom Element Upgrade
WRONG:
// Element created but init() not called yet
const btn = document.createElement("bim-button");
btn.label = "Open"; // Sets property on HTMLElement — lost after upgrade
btn.icon = "mdi:folder"; // Same issue
// Later...
BUI.Manager.init(); // Element upgrades, but properties were set on wrong prototypeCORRECT:
// ALWAYS init first
BUI.Manager.init();
// Now properties are set on the correctly upgraded element
const btn = document.createElement("bim-button");
btn.label = "Open";
btn.icon = "mdi:folder";Alternative (if init order cannot be guaranteed):
await customElements.whenDefined("bim-button");
const btn = document.createElement("bim-button");
btn.label = "Open";Why: Before customElements.define() is called (via BUI.Manager.init()), document.createElement("bim-button") creates a generic HTMLElement. Properties set on this generic element may not transfer correctly when the element is later "upgraded" to the custom element class. This leads to properties appearing to be set but not reflected in the rendered output.
Examples — UI Component Syntax
Version: @thatopen/ui 3.3.x / @thatopen/ui-obc 3.3.x
---
E-001: Full BIM Application Layout (Grid + Toolbar + Panel + Viewport)
The standard BIM viewer layout uses bim-grid to compose toolbar, panel, and viewport into a responsive CSS Grid.
import * as BUI from "@thatopen/ui";
import * as OBC from "@thatopen/components";
import * as OBCF from "@thatopen/components-front";
// ALWAYS init UI before creating any bim-* elements
BUI.Manager.init();
// Engine setup
const components = new OBC.Components();
const worlds = components.get(OBC.Worlds);
const world = worlds.create();
// Viewport — pass to renderer as container
const viewport = document.createElement("bim-viewport");
world.scene = new OBC.SimpleScene(components);
world.renderer = new OBCF.PostproductionRenderer(components, viewport);
world.camera = new OBC.OrthoPerspectiveCamera(components);
components.init();
// Toolbar
const toolbar = document.createElement("bim-toolbar");
const navSection = document.createElement("bim-toolbar-section");
navSection.label = "Navigation";
const orbitBtn = document.createElement("bim-button");
orbitBtn.label = "Orbit";
orbitBtn.icon = "mdi:orbit";
orbitBtn.addEventListener("click", () => {
world.camera.set("Orbit");
});
const fitBtn = document.createElement("bim-button");
fitBtn.label = "Fit All";
fitBtn.icon = "mdi:fit-to-screen";
fitBtn.addEventListener("click", () => {
world.camera.fit(world.meshes);
});
navSection.appendChild(orbitBtn);
navSection.appendChild(fitBtn);
toolbar.appendChild(navSection);
// Panel with sections
const panel = document.createElement("bim-panel");
panel.name = "Properties";
panel.icon = "mdi:information";
const infoSection = document.createElement("bim-panel-section");
infoSection.label = "Model Info";
infoSection.icon = "mdi:cube-outline";
const nameInput = document.createElement("bim-text-input");
nameInput.label = "Project Name";
nameInput.value = "My BIM Project";
infoSection.appendChild(nameInput);
panel.appendChild(infoSection);
// Grid — compose everything
const grid = document.createElement("bim-grid");
grid.layouts = {
main: {
template: `
"toolbar toolbar" auto
"panel viewport" 1fr
/ 320px 1fr
`,
elements: { toolbar, panel, viewport },
},
};
grid.layout = "main";
document.body.appendChild(grid);---
E-002: Toolbar with Grouped Actions
Toolbar sections group related buttons. Toolbar groups create nested subgroups.
BUI.Manager.init();
const toolbar = document.createElement("bim-toolbar");
// --- Navigation section ---
const navSection = document.createElement("bim-toolbar-section");
navSection.label = "Navigation";
const orbitBtn = document.createElement("bim-button");
orbitBtn.label = "Orbit";
orbitBtn.icon = "mdi:orbit";
const planBtn = document.createElement("bim-button");
planBtn.label = "Plan";
planBtn.icon = "mdi:floor-plan";
navSection.appendChild(orbitBtn);
navSection.appendChild(planBtn);
// --- Tools section with nested group ---
const toolsSection = document.createElement("bim-toolbar-section");
toolsSection.label = "Tools";
const measureGroup = document.createElement("bim-toolbar-group");
const lengthBtn = document.createElement("bim-button");
lengthBtn.label = "Length";
lengthBtn.icon = "mdi:ruler";
const areaBtn = document.createElement("bim-button");
areaBtn.label = "Area";
areaBtn.icon = "mdi:square-outline";
measureGroup.appendChild(lengthBtn);
measureGroup.appendChild(areaBtn);
toolsSection.appendChild(measureGroup);
// --- Assemble ---
toolbar.appendChild(navSection);
toolbar.appendChild(toolsSection);---
E-003: Property Panel with Form Elements
A panel with multiple sections containing different input types. The panel aggregates all values via its value property.
BUI.Manager.init();
const panel = document.createElement("bim-panel");
panel.name = "Element Properties";
// --- General section (always visible) ---
const generalSection = document.createElement("bim-panel-section");
generalSection.label = "General";
generalSection.icon = "mdi:information-outline";
generalSection.fixed = true; // cannot be collapsed
const nameInput = document.createElement("bim-text-input");
nameInput.label = "Name";
nameInput.value = "Wall-001";
const heightInput = document.createElement("bim-number-input");
heightInput.label = "Height";
heightInput.value = 3.0;
heightInput.suffix = "m";
heightInput.min = 0.1;
heightInput.max = 100;
heightInput.step = 0.1;
const structuralCheck = document.createElement("bim-checkbox");
structuralCheck.label = "Structural";
structuralCheck.checked = true;
generalSection.appendChild(nameInput);
generalSection.appendChild(heightInput);
generalSection.appendChild(structuralCheck);
// --- Appearance section (collapsible) ---
const appearanceSection = document.createElement("bim-panel-section");
appearanceSection.label = "Appearance";
appearanceSection.icon = "mdi:palette";
appearanceSection.collapsed = true;
const colorInput = document.createElement("bim-color-input");
colorInput.label = "Color";
colorInput.color = "#ff6600";
const materialDropdown = document.createElement("bim-dropdown");
materialDropdown.label = "Material";
const concrete = document.createElement("bim-option");
concrete.label = "Concrete";
concrete.checked = true;
const steel = document.createElement("bim-option");
steel.label = "Steel";
const wood = document.createElement("bim-option");
wood.label = "Wood";
materialDropdown.appendChild(concrete);
materialDropdown.appendChild(steel);
materialDropdown.appendChild(wood);
appearanceSection.appendChild(colorInput);
appearanceSection.appendChild(materialDropdown);
// --- Assemble and listen ---
panel.appendChild(generalSection);
panel.appendChild(appearanceSection);
panel.addEventListener("change", () => {
console.log("Panel values:", panel.value);
// { Name: "Wall-001", Height: 3.0, Structural: true,
// Color: "#ff6600", Material: "Concrete" }
});---
E-004: Data Table with Hierarchy and Selection
Displaying IFC spatial structure data in a bim-table with expandable hierarchy and row selection.
BUI.Manager.init();
const table = document.createElement("bim-table");
// Define columns with custom widths
table.columns = [
{ name: "Name", width: "minmax(200px, 1fr)" },
{ name: "Type", width: "150px" },
{ name: "Level", width: "100px" },
];
// Hierarchical data
table.data = [
{
data: { Name: "Building A", Type: "IfcBuilding", Level: "-" },
children: [
{
data: { Name: "Level 1", Type: "IfcBuildingStorey", Level: "0.000" },
children: [
{ data: { Name: "Wall-001", Type: "IfcWall", Level: "0.000" } },
{ data: { Name: "Wall-002", Type: "IfcWall", Level: "0.000" } },
{ data: { Name: "Slab-001", Type: "IfcSlab", Level: "0.000" } },
],
},
{
data: { Name: "Level 2", Type: "IfcBuildingStorey", Level: "3.500" },
children: [
{ data: { Name: "Wall-003", Type: "IfcWall", Level: "3.500" } },
],
},
],
},
];
// Enable selection
table.selectableRows = true;
table.expanded = true;
// Listen for selection
table.addEventListener("dataselected", (e) => {
const row = e.detail.data;
console.log("Selected:", row.Name, row.Type);
});
table.addEventListener("datadeselected", (e) => {
console.log("Deselected:", e.detail.data.Name);
});Filtering the Table
// Simple text filter — searches all columns
table.queryString = "wall";
// Column-specific query
table.queryString = 'Type="IfcWall" & Level="0.000"';
// Custom filter function
table.filterFunction = (row) => {
return row.data.Type === "IfcWall";
};
// Group by column
table.groupedBy = "Level";
// Export to CSV
table.downloadData("elements", "csv");---
E-005: Using @thatopen/ui-obc Functional Components
Pre-built BIM UI components that wire directly to the ThatOpen engine.
import * as BUI from "@thatopen/ui";
import * as OBC from "@thatopen/components";
import * as OBCF from "@thatopen/components-front";
import * as CUI from "@thatopen/ui-obc";
BUI.Manager.init();
const components = new OBC.Components();
// ... world setup omitted for brevity ...
const fragments = components.get(OBC.FragmentsManager);
// --- IFC Load Button ---
const [loadIfcBtn, updateLoadIfcBtn] = CUI.buttons.loadIfc({ components });
// --- Spatial Tree ---
const [spatialTree, updateSpatialTree] = CUI.tables.spatialTree({
components,
models: [],
});
// Update the tree when a model is loaded
fragments.onFragmentsLoaded.add((model) => {
updateSpatialTree({ models: [model] });
});
// --- Models List ---
const [modelsList, updateModelsList] = CUI.tables.modelsList({ components });
// --- Compose into panel ---
const panel = document.createElement("bim-panel");
panel.name = "Model Browser";
const treeSection = document.createElement("bim-panel-section");
treeSection.label = "Spatial Structure";
treeSection.appendChild(spatialTree);
const modelsSection = document.createElement("bim-panel-section");
modelsSection.label = "Models";
modelsSection.appendChild(modelsList);
panel.appendChild(treeSection);
panel.appendChild(modelsSection);
// --- Add load button to toolbar ---
const toolbar = document.createElement("bim-toolbar");
const fileSection = document.createElement("bim-toolbar-section");
fileSection.label = "File";
fileSection.appendChild(loadIfcBtn);
toolbar.appendChild(fileSection);---
E-006: CSS Theming — Custom Dark Theme
Override CSS custom properties to create a branded dark theme.
/* Apply to root or any container element */
:root {
--bim-ui_bg-base: #0d1117;
--bim-ui_bg-contrast-10: #161b22;
--bim-ui_bg-contrast-20: #21262d;
--bim-ui_bg-contrast-40: #30363d;
--bim-ui_bg-contrast-60: #484f58;
--bim-ui_bg-contrast-80: #8b949e;
--bim-ui_bg-contrast-100: #c9d1d9;
--bim-ui_accent-base: #238636;
--bim-ui_accent-contrast: #ffffff;
--bim-ui_font-family: "JetBrains Mono", monospace;
--bim-ui_size-base: 0.3rem;
}Scoped Theming
Override properties on a specific container to theme only part of the UI:
/* Only this panel gets custom colors */
#settings-panel {
--bim-ui_bg-base: #1e293b;
--bim-ui_accent-base: #3b82f6;
}---
E-007: Panel Toggle with Activation Button
Every bim-panel creates an activationButton that toggles visibility.
BUI.Manager.init();
const panel = document.createElement("bim-panel");
panel.name = "Properties";
panel.hidden = true; // start hidden
// Get the auto-created toggle button
const toggleBtn = panel.activationButton;
toggleBtn.label = "Properties";
toggleBtn.icon = "mdi:dock-right";
// Place in toolbar
const toolbar = document.createElement("bim-toolbar");
const viewSection = document.createElement("bim-toolbar-section");
viewSection.label = "View";
viewSection.appendChild(toggleBtn);
toolbar.appendChild(viewSection);
// Listen for visibility changes
panel.addEventListener("hiddenchange", () => {
console.log("Panel visible:", !panel.hidden);
});---
E-008: Layout Switching with Grid
Switch between different layouts at runtime (e.g., full viewport vs. split view).
BUI.Manager.init();
const grid = document.createElement("bim-grid");
grid.layouts = {
split: {
template: `
"toolbar toolbar" auto
"panel viewport" 1fr
/ 320px 1fr
`,
elements: { toolbar, panel, viewport },
},
fullscreen: {
template: `
"toolbar" auto
"viewport" 1fr
/ 1fr
`,
elements: { toolbar, viewport },
},
};
grid.layout = "split";
// Toggle layout button
const toggleLayoutBtn = document.createElement("bim-button");
toggleLayoutBtn.label = "Toggle Layout";
toggleLayoutBtn.icon = "mdi:fullscreen";
toggleLayoutBtn.addEventListener("click", () => {
grid.layout = grid.layout === "split" ? "fullscreen" : "split";
});
// Listen for layout changes
grid.addEventListener("layoutchange", () => {
console.log("Current layout:", grid.layout);
});---
E-009: Tabs for Multiple Panels
Use bim-tabs to organize multiple views within a single panel area.
<bim-panel name="Inspector">
<bim-tabs>
<bim-tab label="Properties" icon="mdi:format-list-bulleted">
<bim-panel-section label="Attributes" icon="mdi:tag">
<bim-text-input label="Name" value="Wall-001"></bim-text-input>
<bim-text-input label="GlobalId" value="2O2Fr$t4X7Z..."></bim-text-input>
</bim-panel-section>
</bim-tab>
<bim-tab label="Relations" icon="mdi:link-variant">
<bim-panel-section label="Contains" icon="mdi:folder-open">
<!-- relation content -->
</bim-panel-section>
</bim-tab>
</bim-tabs>
</bim-panel>---
E-010: Resizable Grid Areas
Enable the user to drag-resize grid areas at runtime.
BUI.Manager.init();
const grid = document.createElement("bim-grid");
grid.resizeableAreas = true;
// Prevent the toolbar area from being resized
grid.areasResizeExceptions = ["toolbar"];
grid.layouts = {
main: {
template: `
"toolbar toolbar" auto
"panel viewport" 1fr
/ 320px 1fr
`,
elements: { toolbar, panel, viewport },
},
};
grid.layout = "main";
// The user can now drag the border between panel and viewport.
// The toolbar row is excluded from resize interactions.API Signatures — UI Component Syntax
Version: @thatopen/ui 3.3.x / @thatopen/ui-obc 3.3.x
---
BUI.Manager
class Manager {
/**
* Registers all bim-* custom elements and injects global styles.
* MUST be called once before any bim-* element is used.
* @param querySelectorElements — CSS selector for animation targets (optional)
* @param animateOnLoad — enable entrance animations (default: true)
*/
static init(
querySelectorElements?: string,
animateOnLoad?: boolean
): void;
/**
* Toggles between bim-ui-dark and bim-ui-light CSS classes on <html>.
* @param animate — show overlay transition animation (default: false)
*/
static toggleTheme(animate?: boolean): void;
/**
* Preloads Iconify icon collections for offline use.
* @param collections — array of collection names (e.g., ["mdi", "material-symbols"])
* @param log — log loading status to console (default: false)
*/
static preloadIcons(collections: string[], log?: boolean): Promise<void>;
/** Injects global BIM UI stylesheet into document head (idempotent). */
static addGlobalStyles(): void;
/** Generates a random 10-character alphanumeric ID. */
static newRandomId(): string;
/** Runtime configuration. */
static config: ManagerConfig;
}
interface ManagerConfig {
/** Show section labels on vertical toolbars. Default: false. */
sectionLabelOnVerticalToolbar: boolean;
/** Attribute name for internal component identification. */
internalComponentNameAttribute: string;
}---
Layout Components
bim-grid
// Custom element: <bim-grid>
interface BimGrid extends LitElement {
/** Name of the active layout from the layouts collection. */
layout: string; // reflects
/** Whether the grid floats (absolute position, no pointer-events on gaps). */
floating: boolean; // reflects, default: false
/** Enable interactive resize handles between grid areas. */
resizeableAreas: boolean; // attribute: areas-resizeable, default: false
/** Areas excluded from resizing when resizeableAreas is true. */
areasResizeExceptions: string[];
/** Collection of named layout definitions. */
layouts: GridLayoutsDefinition;
/** Map of area names to HTML elements. */
elements: GridComponents;
/** State update functions for stateful elements. */
updateComponent: UpdateGridComponents;
/** Stored resize dimensions per layout (after user resizing). */
layoutsResize: Record<string, object>;
}
// Events
"layoutchange" // layout property changed
"elementcreated" // element instantiated for an area
interface GridLayoutsDefinition {
[name: string]: {
template: string; // CSS grid-template value
elements: GridComponents; // area name -> HTMLElement
guard?: () => boolean; // conditional rendering
};
}bim-panel
// Custom element: <bim-panel>
interface BimPanel extends LitElement {
icon: string; // reflects
name: string; // reflects
label: string; // reflects
hidden: boolean; // reflects, default: false
headerHidden: boolean; // reflects, default: false
value: Record<string, any>; // aggregated form values (readonly)
valueTransform: Record<string, (v: any) => any>;
activationButton: BimButton; // auto-created toggle button
}
// Events
"change" // form value changed in any child element
"hiddenchange" // hidden property toggled
// Slots
// default — accepts bim-panel-section elementsbim-panel-section
// Custom element: <bim-panel-section>
interface BimPanelSection extends LitElement {
label: string; // reflects
icon: string; // reflects
collapsed: boolean; // reflects, default: false
fixed: boolean; // reflects — prevents collapsing
}
// Slots
// default — accepts any form elements or contentbim-toolbar
// Custom element: <bim-toolbar>
interface BimToolbar extends LitElement {
icon: string; // reflects
vertical: boolean; // reflects, default: false
labelsHidden: boolean; // reflects, default: false
hidden: boolean; // reflects, default: false
}
// Events
"hiddenchange" // hidden property toggled
// Slots
// default — accepts bim-toolbar-section elementsbim-toolbar-section
// Custom element: <bim-toolbar-section>
interface BimToolbarSection extends LitElement {
label: string; // reflects
icon: string; // reflects
vertical: boolean; // reflects, default: false
}
// Slots
// default — accepts bim-button or bim-toolbar-group elementsbim-toolbar-group
// Custom element: <bim-toolbar-group>
interface BimToolbarGroup extends LitElement {
vertical: boolean; // reflects, default: false
}
// Slots
// default — accepts bim-button elementsbim-viewport
// Custom element: <bim-viewport>
interface BimViewport extends LitElement {
// Wraps a canvas/container element for the 3D renderer.
// Pass this element as the container to SimpleRenderer
// or PostproductionRenderer.
}bim-tabs / bim-tab
// Custom element: <bim-tabs>
interface BimTabs extends LitElement {
// Manages active tab state.
}
// Custom element: <bim-tab>
interface BimTab extends LitElement {
label: string; // reflects
icon: string; // reflects
}---
Interactive Components
bim-button
// Custom element: <bim-button>
interface BimButton extends LitElement {
label: string; // reflects
icon: string; // reflects
disabled: boolean; // reflects, default: false
active: boolean; // reflects, default: false
vertical: boolean; // reflects, default: false
tooltipTitle: string; // reflects
tooltipText: string; // reflects
}
// Events
"click" // standard MouseEventbim-checkbox
// Custom element: <bim-checkbox>
interface BimCheckbox extends LitElement {
label: string; // reflects
checked: boolean; // reflects, default: false
inverted: boolean; // reflects, default: false
}
// Events
"change" // checked state toggledbim-text-input
// Custom element: <bim-text-input>
interface BimTextInput extends LitElement {
label: string; // reflects
value: string;
placeholder: string; // reflects
vertical: boolean; // reflects, default: false
}
// Events
"input" // value changed during typing
"change" // value committedbim-number-input
// Custom element: <bim-number-input>
interface BimNumberInput extends LitElement {
label: string; // reflects
value: number;
min: number; // reflects
max: number; // reflects
step: number; // reflects
suffix: string; // reflects (unit label, e.g., "m")
vertical: boolean; // reflects, default: false
slider: boolean; // reflects — show as slider
pref: string; // prefix text
}
// Events
"change" // value changedbim-color-input
// Custom element: <bim-color-input>
interface BimColorInput extends LitElement {
label: string; // reflects
color: string; // hex color value
opacity: number; // 0-1
}
// Events
"change" // color or opacity changedbim-dropdown
// Custom element: <bim-dropdown>
interface BimDropdown extends LitElement {
label: string; // reflects
multiple: boolean; // reflects, default: false
required: boolean; // reflects, default: false
visible: boolean; // reflects — dropdown open state
value: Record<string, string>[]; // selected options
}
// Events
"change" // selection changed
// Slots
// default — accepts bim-option elementsbim-option
// Custom element: <bim-option>
interface BimOption extends LitElement {
label: string; // reflects
value: string; // reflects
checked: boolean; // reflects, default: false
icon: string; // reflects
img: string; // reflects
checkbox: boolean; // reflects — show checkbox indicator
}bim-selector
// Custom element: <bim-selector>
interface BimSelector extends LitElement {
label: string; // reflects
multiple: boolean; // reflects, default: false
}
// Events
"change" // selection changed
// Slots
// default — accepts bim-option elements---
Display Components
bim-label
// Custom element: <bim-label>
interface BimLabel extends LitElement {
icon: string; // reflects — Iconify icon name
img: string; // reflects — image URL
}
// Slots
// default — text contentbim-icon
// Custom element: <bim-icon>
interface BimIcon extends LitElement {
icon: string; // reflects — Iconify icon name
}bim-table
// Custom element: <bim-table>
interface BimTable extends LitElement {
/** Row data with optional hierarchy. */
data: TableGroupData[];
/** Column definitions or simple name strings. */
columns: (ColumnData | string)[];
/** Computed filtered/grouped data (readonly). */
value: TableGroupData[];
/** Hide column headers. */
headersHidden: boolean; // default: false
/** Minimum column width. */
minColWidth: string; // default: "4rem"
/** Expand all grouped rows. */
expanded: boolean; // default: false
/** Show loading indicator. */
loading: boolean; // default: false
/** Remove row indentation for children. */
noIndentation: boolean; // default: false
/** Hide expand/collapse carets. */
noCarets: boolean; // default: false
/** Enable row selection. */
selectableRows: boolean; // default: false
/** Set of selected row data. */
selection: DataSet<object>;
/** Simple text or column query filter. */
queryString: string;
/** Columns to group by. */
groupedBy: string | string[];
/** Keep hierarchy when filtering. */
preserveStructureOnFilter: boolean; // default: false
/** Custom filter function. */
filterFunction: (data: any) => boolean;
/** Transform functions per column. */
dataTransform: Record<string, (v: any) => any>;
/** Default column visibility. */
defaultVisibility: boolean; // default: true
visibilityExceptions: string[];
hiddenColumns: string[]; // setter
visibleColumns: string[]; // setter
/** Export table data. */
downloadData(fileName: string, format: "csv" | "tsv"): void;
}
interface TableGroupData<T = Record<string, any>> {
data: Partial<T>;
children?: TableGroupData<T>[];
}
interface ColumnData {
name: string;
width?: string; // CSS grid size, default: "minmax(minColWidth, 1fr)"
forceDataTransform?: boolean;
}
// Events
"columnschange" // columns updated
"dataselected" // row selected, detail: { data }
"datadeselected" // row deselected, detail: { data }
"dataselectioncleared" // all selection cleared
"connected" // component mounted
"disconnected" // component unmountedbim-tooltip
// Custom element: <bim-tooltip>
interface BimTooltip extends LitElement {
// Renders tooltip content on hover over parent element.
}bim-context-menu
// Custom element: <bim-context-menu>
interface BimContextMenu extends LitElement {
// Right-click context menu with positioned overlay.
}bim-chart / bim-chart-legend
// Custom element: <bim-chart>
interface BimChart extends LitElement {
// Data visualization chart component.
}
// Custom element: <bim-chart-legend>
interface BimChartLegend extends LitElement {
// Legend for chart component.
}---
CSS Custom Properties Reference
All properties use the --bim-ui_ prefix and can be overridden at any DOM level.
Background Colors
| Property | Default (Dark) | Description |
|---|---|---|
--bim-ui_bg-base | #1a1a2e | Primary background |
--bim-ui_bg-contrast-10 | #232340 | Subtle contrast layer |
--bim-ui_bg-contrast-20 | #2c2c4a | Borders, dividers |
--bim-ui_bg-contrast-40 | #3d3d5c | Muted elements |
--bim-ui_bg-contrast-60 | #5a5a7a | Secondary text |
--bim-ui_bg-contrast-80 | #8888a8 | Primary text |
--bim-ui_bg-contrast-100 | #ffffff | Maximum contrast |
Accent Colors
| Property | Default | Description |
|---|---|---|
--bim-ui_accent-base | #6528d7 | Primary accent (buttons, links) |
--bim-ui_accent-contrast | #ffffff | Text on accent backgrounds |
Sizing Scale
| Property | Default | Description |
|---|---|---|
--bim-ui_size-base | 0.25rem | Base unit for spacing/radius |
--bim-ui_size-2xs | 0.125rem | Extra-extra-small |
--bim-ui_size-xs | 0.25rem | Extra-small |
--bim-ui_size-sm | 0.75rem | Small (label font-size) |
--bim-ui_size-md | 1rem | Medium |
--bim-ui_size-lg | 1.25rem | Large |
--bim-ui_size-xl | 1.5rem | Extra-large |
Typography
| Property | Default | Description |
|---|---|---|
--bim-ui_font-family | "Inter", sans-serif | Global font family |
Component-Specific Overrides
/* Override label styling on a specific element */
bim-label {
--bim-label--c: #ff0000; /* text color */
--bim-label--fz: 14px; /* font size */
}---
@thatopen/ui-obc Factory Functions
All ui-obc components are factory functions returning [HTMLElement, UpdateFunction].
Tables
// Spatial structure tree
CUI.tables.spatialTree(config: {
components: OBC.Components;
models: OBC.FragmentsModel[];
}): [HTMLElement, (config: Partial<typeof config>) => void];
// Element property data
CUI.tables.itemsData(config: {
components: OBC.Components;
}): [HTMLElement, (config: Partial<typeof config>) => void];
// Loaded models list
CUI.tables.modelsList(config: {
components: OBC.Components;
}): [HTMLElement, (config: Partial<typeof config>) => void];
// BCF viewpoints table
CUI.tables.viewpointsList(config: {
components: OBC.Components;
}): [HTMLElement, (config: Partial<typeof config>) => void];
// BCF topics table
CUI.tables.topicsList(config: {
components: OBC.Components;
}): [HTMLElement, (config: Partial<typeof config>) => void];
// BCF comments table
CUI.tables.commentsList(config: {
components: OBC.Components;
}): [HTMLElement, (config: Partial<typeof config>) => void];Buttons
// IFC file load button
CUI.buttons.loadIfc(config: {
components: OBC.Components;
}): [HTMLElement, (config: Partial<typeof config>) => void];
// Fragment file load button
CUI.buttons.loadFrag(config: {
components: OBC.Components;
}): [HTMLElement, (config: Partial<typeof config>) => void];Sections
// BCF topic information panel
CUI.sections.topicInformation(config: {
components: OBC.Components;
}): [HTMLElement, (config: Partial<typeof config>) => void];
// BCF topic comments panel
CUI.sections.topicComments(config: {
components: OBC.Components;
}): [HTMLElement, (config: Partial<typeof config>) => void];
// BCF topic relations panel
CUI.sections.topicRelations(config: {
components: OBC.Components;
}): [HTMLElement, (config: Partial<typeof config>) => void];
// BCF topic viewpoints panel
CUI.sections.topicViewpoints(config: {
components: OBC.Components;
}): [HTMLElement, (config: Partial<typeof config>) => void];