@knime/kds-code-editor
v11.5.0
Published
Package containing the code editor component of the KNIME Design System
Readme
KNIME® Design System – Code Editor
This is part of the KNIME Design System maintained by the UI Core Team.
This package contains the KdsCodeEditor, KdsCodeDiffEditor, and KdsConsole components, which follow the KNIME Design System. They are based on the Vue JavaScript framework; the editors are powered by the Monaco editor and the console by xterm.js.
It's published as npm package: @knime/kds-code-editor
Why a separate package?
Monaco is a large dependency (the editor core plus language workers) that is irrelevant to most consumers of @knime/kds-components. Keeping the code editor in its own package keeps that dependency, bundle, and security-audit/SBOM surface opt-in — only apps that install this package pull it in.
monaco-editor is declared as a peer dependency and is externalized in the build (see vite.config.ts): Monaco holds global state (language registry, MonacoEnvironment, models), so the host app controls the single shared instance and can pull CVE-patched versions via its own lockfile without waiting on a republish.
Setup in consuming repositories
Peer dependency
monaco-editor is a peer dependency (see Why a separate package?). Install a version matching the peer range declared in package.json.
Monaco patch (required)
Two upstream Monaco bugs are fixed by a
pnpm patch that ships with this
package under patches/:
- Monaco's hover, suggest, and action widgets mis-position and mis-detect mouse leave when the editor is rendered inside a shadow root — which is how KNIME embeds UI extensions (AP-25740).
- Dropping text into the editor appends a literal
$0(and backslash-escapes$,\,}) because standalone Monaco's bulk edit service ignores theinsertAsSnippetflag set by the drop/paste handlers (microsoft/monaco-editor#4386).
Because pnpm applies patches in the installing workspace (a package cannot
patch its consumer's dependencies), every consuming repository must apply it
to its own monaco-editor install:
Copy
node_modules/@knime/kds-code-editor/patches/monaco-editor@<version>.patchinto your repository (e.g. apatches/folder). Do not reference the file insidenode_modulesdirectly — on a cold install pnpm needs the patch before the package providing it is extracted.Register it in your
pnpm-workspace.yaml:patchedDependencies: [email protected]: patches/[email protected]
When this package bumps its monaco-editor peer range, the bundled patch is
updated with it — re-copy the patch file when you bump Monaco.
Monaco state is global
Standalone Monaco keeps page-global state, and KdsCodeEditor and
KdsCodeDiffEditor participate in it:
- Theme: the components switch Monaco's built-in
vs-light/vs-darktheme to follow the KDS dark-mode setting — once at mount and again on every dark-mode change. Monaco's theme applies to every standalone editor on the page, so the host app's own Monaco editors switch along with it, and a custom theme set by the host is overridden while one of them is mounted. If your app defines its own Monaco editors, expect them to render withvs-light/vs-darkalongside these components. - Worker environment and languages:
setupMonacoEnvironment(called by both editor components on setup) installs aMonacoEnvironmentonly when the host app has not already defined one, and registers the custom language grammars shipped with this package (e.g.toml) in Monaco's global language registry — they are then also available to the host app's own editors.
Using the editor in a Vue application
Install the @knime/kds-code-editor npm package together with @knime/kds-styles. It declares monaco-editor, vue, and @vueuse/core as peer dependencies:
pnpm add @knime/kds-code-editor @knime/kds-styles monaco-editor vue @vueuse/coreThe components use the KDS CSS variables but do not load them. Import them once in your app (e.g. in main.ts):
import "@knime/kds-styles/kds-variables.css";<script setup lang="ts">
import { ref } from "vue";
import { KdsCodeEditor } from "@knime/kds-code-editor";
const value = ref('key = "value"');
</script>
<template>
<KdsCodeEditor v-model="value" language="toml" :min-rows="5" />
</template>Public exports
All public symbols follow the KDS Kds prefix convention:
| Export | Kind | Description |
| --------------------------------- | --------- | ------------------------------------------------------------------ |
| KdsCodeEditor | component | The code editor (with header, copy button, and sub-text) |
| KdsCodeDiffEditor | component | Side-by-side or inline diff editor with an optional change summary |
| KdsConsole | component | Read-only output console (xterm.js based) |
| setupMonacoEnvironment | function | Installs the Monaco worker environment (no-op if already set) |
| kdsCodeEditorState | const | Editor states (default / error / warning) |
| kdsCodeEditorStates | const | Array of all editor states |
| KdsCodeEditorProps | type | Props of KdsCodeEditor |
| KdsCodeDiffEditorProps | type | Props of KdsCodeDiffEditor |
| KdsConsoleHandler | type | Handle for writing to / clearing a KdsConsole |
| KdsConsoleText | type | A console line ({ text }, { warning }, or { error }) |
| KdsCodeEditorState | type | Union of the editor states |
| KdsCodeEditorAction | type | Union of the header action types below |
| KdsCodeEditorButtonAction | type | Header action rendered as KdsButton |
| KdsCodeEditorToggleButtonAction | type | Header action rendered as KdsToggleButton |
| KdsCodeEditorMenuButtonAction | type | Header action rendered as KdsMenuButton |
KdsConsole exposes its writer through the console-created event rather than
props — store the handler and call write / writeln / clear from your app.
The console fills its parent (height: 100%), so give the parent a height:
<script setup lang="ts">
import { KdsConsole, type KdsConsoleHandler } from "@knime/kds-code-editor";
const onConsoleCreated = (handler: KdsConsoleHandler) => {
handler.writeln({ text: "Execution started" });
handler.writeln({ warning: "Deprecated option used" });
};
</script>
<template>
<div style="height: 200px">
<KdsConsole @console-created="onConsoleCreated" />
</div>
</template>Using with Vitest, Nuxt, or Vite SSR
The published JavaScript imports its CSS as a side effect (e.g.
import "./index.css"), which bundlers handle automatically. When the package
is instead evaluated by Node's native ESM loader — as Vitest and
Vite/Nuxt SSR do by default, since they externalize node_modules — Node
has no .css loader and throws Unknown file extension ".css". Configure the
consuming project once so @knime/* packages are processed instead of
externalized:
// Vitest — vitest.config.ts
export default defineConfig({
test: { server: { deps: { inline: [/@knime\//] } } },
});// Vite SSR — vite.config.ts
export default defineConfig({ ssr: { noExternal: [/@knime\//] } });// Nuxt — nuxt.config.ts
export default defineNuxtConfig({ build: { transpile: [/@knime\//] } });