
Security News
RubyGems Adds Cooldown Feature to Bundler for Newly Published Gems
RubyGems and Bundler 4.0.13 introduced an opt-in cooldown feature that delays newly published gems during dependency resolution.
@editora/light-code-editor
Advanced tools
Lightweight code editor for React and web apps with syntax highlighting, search/replace, extensions, and enterprise SaaS integration patterns.
[!IMPORTANT] Live Website: https://editora-ecosystem.netlify.app/
Storybook: https://editora-ecosystem-storybook.netlify.app/
A lightweight, modular code editor library inspired by CodeMirror, optimized for embedding inside rich text editors.
✅ Self-Contained Library - Everything needed (including CSS) is bundled within the library ✅ Modular Architecture - Extension-based system for maximum flexibility ✅ Syntax Highlighting - Built-in highlighting for HTML, CSS, JavaScript/JSX, TypeScript/TSX, JSON, Markdown, Bash/Shell, Python, Go, C/C++, Java, C#, Rust, Ruby, SQL, YAML, XML/SVG, Vue, EJS, Dockerfile, and PHP ✅ Themes - Light and dark theme support ✅ Line Numbers - Optional line number gutter ✅ Search - Find and highlight functionality ✅ Diagnostics - Gutter markers, inline issue highlights, and issue navigation ✅ Completions - Provider-based autocomplete popup with keyboard navigation ✅ Formatting - Pluggable document and selection formatting with async safety ✅ Context Menus - Right-click actions for search, replace, formatting, and navigation ✅ Editing Commands - Toggle comments, duplicate/move lines, join lines, and go to line ✅ Active Line & Indent Guides - Caret-aware line highlighting with low-overhead indentation guides ✅ Language Service Adapter - Compose syntax, diagnostics, completions, formatting, hover tooltips, and code actions from one shared service contract ✅ Bracket Matching - Automatic bracket pair highlighting ✅ Code Folding - Collapse/expand code sections ✅ Read-Only Mode - Prevent text modifications ✅ TypeScript Support - Full TypeScript definitions ✅ Zero Dependencies - Pure JavaScript implementation
npm install @editora/light-code-editor
import {
BracketMatchingExtension,
CodeFoldingExtension,
CompletionExtension,
ContextMenuExtension,
DiagnosticsExtension,
ActiveLineAndIndentGuidesExtension,
EditingCommandsExtension,
FormattingExtension,
LineNumbersExtension,
SearchExtension,
SyntaxHighlightingExtension,
createEditor
} from '@editora/light-code-editor';
import '@editora/light-code-editor/light-code-editor.css';
const container = document.getElementById('editor');
if (!container) {
throw new Error('Missing #editor container');
}
const editor = createEditor(container, {
value: '<div class="hello">Hello World</div>\n',
theme: 'dark',
tabSize: 2,
lineNumbers: true,
lineWrapping: false,
extensions: [
new LineNumbersExtension(),
new SyntaxHighlightingExtension(),
new SearchExtension(),
new DiagnosticsExtension(),
new CompletionExtension(),
new FormattingExtension(),
new ContextMenuExtension(),
new EditingCommandsExtension(),
new ActiveLineAndIndentGuidesExtension(),
new BracketMatchingExtension(),
new CodeFoldingExtension()
]
});
editor.on('change', (changes) => {
console.log('Content changed:', changes);
});
editor.executeCommand('find');
const cleanup = () => {
editor.destroy();
};
createEditor(container, config)Factory function to create a new editor instance.
container: HTMLElement - The DOM element to attach the editor toconfig: EditorConfig - Configuration optionsinterface EditorConfig {
value?: string;
theme?: string;
readOnly?: boolean;
tabSize?: number;
lineWrapping?: boolean;
lineNumbers?: boolean;
extensions?: EditorExtension[];
keymap?: Keymap;
}
Common config flags:
tabSize: applies CSS tab rendering width in the editable surfacelineWrapping: toggles pre vs pre-wrap renderinglineNumbers: controls the gutter at startup and at runtime through the line-numbers extensionkeymap: custom shortcut bindings used by the default KeymapExtensioninterface EditorAPI {
getValue(): string;
setValue(value: string): void;
getState(): EditorState;
getCursor(): Cursor;
setCursor(position: Position): void;
getSelection(): Range | undefined;
setSelection(range: Range): void;
setTheme(theme: string): void;
setReadOnly(readOnly: boolean): void;
addExtension(extension: EditorExtension): void;
removeExtension(name: string): void;
executeCommand(name: string, ...args: any[]): void;
setDecorations(layer: string, decorations: EditorDecoration[]): void;
clearDecorations(layer?: string): void;
getDecorations(layer?: string): EditorDecoration[];
registerCommand(name: string, handler: Function): void;
search(query: string, options?: Partial<SearchOptions>): SearchResult[];
replace(range: Range, text: string): void;
replaceAll(query: string, replacement: string, options?: Partial<SearchOptions>): number;
fold(range: Range): void;
unfold(range: Range): void;
getFolds(): FoldRange[];
focus(): void;
blur(): void;
destroy(): void;
on(event: string, handler: Function): void;
off(event: string, handler: Function): void;
}
For extension authors, the editor also exposes getView() and getConfig() so custom extensions can coordinate with the rendered surface and startup config.
The editor now exposes a lightweight decorations surface for features like diagnostics, active-line styling, inline markers, and gutter badges.
import type { EditorDecoration } from '@editora/light-code-editor';
const decorations: EditorDecoration[] = [
{
id: 'active-line',
type: 'line',
line: 3,
className: 'lce-decoration-line--active'
},
{
id: 'error-gutter',
type: 'gutter',
line: 3,
label: '●',
title: 'Syntax error',
className: 'lce-decoration-gutter--error'
},
{
id: 'error-inline',
type: 'inline',
range: {
start: { line: 3, column: 10 },
end: { line: 3, column: 18 }
},
style: {
backgroundColor: 'rgba(255, 107, 107, 0.18)',
textDecoration: 'underline wavy rgba(255, 107, 107, 0.95)'
}
}
];
editor.setDecorations('diagnostics', decorations);
Notes:
line and gutter decorations render in dedicated overlay layers without replacing the editable DOM.inline decorations use the browser CSS Highlight API when available, which keeps range rendering fast and selection-safe.setDecorations('diagnostics', nextDecorations) with the full next set for that layer.clearDecorations('diagnostics') removes one layer, while clearDecorations() clears all layers.LineNumbersExtensionAdds line numbers to the left gutter.
import { LineNumbersExtension } from '@editora/light-code-editor';
const editor = createEditor(container, {
extensions: [new LineNumbersExtension()]
});
SyntaxHighlightingExtensionProvides built-in syntax highlighting for html, css, javascript / js, jsx, typescript / ts, tsx, json, markdown / md, bash / shell / sh / zsh, python / py, go / golang, c, cpp / c++, java, csharp / cs, rust / rs, ruby / rb, sql, yaml / yml, xml / svg, vue, ejs, dockerfile / docker, and php.
import { SyntaxHighlightingExtension } from '@editora/light-code-editor';
const syntax = new SyntaxHighlightingExtension();
const editor = createEditor(container, {
extensions: [syntax]
});
editor.executeCommand('setSyntaxLanguage', 'json');
Notes:
html.setSyntaxLanguage to switch the active built-in mode at runtime.syntax.registerMode(languageId, mode) to add custom modes.ThemeExtensionEnables theme switching.
import { ThemeExtension } from '@editora/light-code-editor';
const editor = createEditor(container, {
extensions: [new ThemeExtension()]
});
ReadOnlyExtensionAdds read-only mode functionality.
import { ReadOnlyExtension } from '@editora/light-code-editor';
const editor = createEditor(container, {
extensions: [new ReadOnlyExtension()]
});
SearchExtensionProvides search and replace functionality.
import { SearchExtension } from '@editora/light-code-editor';
const editor = createEditor(container, {
extensions: [
new SearchExtension({
// Replace mode defaults to true and advances to the next match
// after each Enter press in the replace field.
replaceAndFindNext: true
})
]
});
Advanced find/replace UI supports:
Aa for case-sensitive searchWhole for whole-word-only matching.* for regular-expression searchIf regex input is invalid, the status shows Invalid regular expression and matching is skipped until the pattern is fixed.
DiagnosticsExtensionProvides diagnostics rendering, issue navigation, and a lightweight status summary.
import {
DiagnosticsExtension,
type EditorDiagnostic,
} from '@editora/light-code-editor';
const diagnostics = new DiagnosticsExtension();
const editor = createEditor(container, {
extensions: [diagnostics]
});
diagnostics.setDiagnostics([
{
severity: 'error',
message: 'Unexpected token',
source: 'demo',
code: 'TS1005',
range: {
start: { line: 2, column: 8 },
end: { line: 2, column: 19 }
}
}
]);
Notes:
nextDiagnostic and prevDiagnostic move focus through the current issue set.clearOnChange: true when you want diagnostics cleared after edits instead of waiting for a provider refresh.CompletionExtensionProvides provider-based autocomplete suggestions with async-safe refresh, popup navigation, and insertion commands.
import {
CompletionExtension,
type CompletionContext,
} from '@editora/light-code-editor';
const completion = new CompletionExtension({
providers: [
(context: CompletionContext) => {
if (context.prefix.startsWith('di')) {
return [
{ label: 'div', kind: 'tag', detail: '<div>' },
{ label: 'dialog', kind: 'tag', detail: '<dialog>' }
];
}
return [];
}
]
});
const editor = createEditor(container, {
extensions: [completion]
});
editor.executeCommand('showCompletions');
Notes:
Ctrl/Cmd + Space opens completions manually.ArrowUp, ArrowDown, Enter, Tab, and Escape work while the popup is open.{ items, from } objects when they need to override the replacement range.FormattingExtensionProvides pluggable document and selection formatting with timeout handling, cancellation, and selection preservation.
import {
FormattingExtension,
createLightweightFormatter,
} from '@editora/light-code-editor';
const formatting = new FormattingExtension({
formatter: createLightweightFormatter(),
timeoutMs: 3000,
});
const editor = createEditor(container, {
extensions: [formatting]
});
editor.executeCommand('formatDocument');
editor.executeCommand('formatSelection');
Notes:
Shift + Alt + F runs formatDocument through the default keymap.AbortSignal.{ text, range, selection, cursor } gives the formatter explicit control over the applied edit and final editor state.createLightweightFormatter() provides dependency-free formatting for common snippets. It is conservative and safe for HTML, CSS, PHP, Python, Bash, Go, C/C++, Java, C#, Rust, Vue, JSX/TSX, EJS, Dockerfile, and plain text, but it is not a replacement for dedicated formatters like Prettier, Black, gofmt, or php-cs-fixer.ContextMenuExtensionProvides a right-click menu that can expose editor commands like find, replace, formatting, undo/redo, and diagnostics navigation.
import {
ContextMenuExtension,
type ContextMenuItem,
} from '@editora/light-code-editor';
const items: ContextMenuItem[] = [
{ label: 'Find', command: 'find', shortcut: 'Ctrl/Cmd+F' },
{ label: 'Find & Replace', command: 'replace', shortcut: 'Ctrl/Cmd+H' },
{ type: 'separator' },
{ label: 'Format Document', command: 'formatDocument', shortcut: 'Shift+Alt+F' },
];
const contextMenu = new ContextMenuExtension({ items });
const editor = createEditor(container, {
extensions: [contextMenu]
});
Notes:
openContextMenu and closeContextMenu commands when you want to trigger the menu programmatically.EditingCommandsExtensionProvides lightweight authoring commands for comments and line editing without requiring a full language service.
import { EditingCommandsExtension } from '@editora/light-code-editor';
const editingCommands = new EditingCommandsExtension({
lineCommentToken: '//',
blockCommentTokens: {
open: '/* ',
close: ' */',
},
});
const editor = createEditor(container, {
extensions: [editingCommands]
});
editor.executeCommand('toggleLineComment');
editor.executeCommand('duplicateLine');
editor.executeCommand('goToLine', 12);
Notes:
toggleLineComment, toggleBlockComment, duplicateLine, moveLineUp, moveLineDown, joinLines, and goToLine.goToLine(12) jumps immediately. Calling goToLine() with no argument opens an inline go-to-line panel inside the editor, similar to find.Ctrl/Cmd + /, Alt + Shift + A, Ctrl/Cmd + Shift + D, Alt + Up/Down, Ctrl/Cmd + J, and Ctrl/Cmd + L for go to line.ActiveLineAndIndentGuidesExtensionHighlights the active line and renders indentation guides through the existing line-decoration pipeline.
import { ActiveLineAndIndentGuidesExtension } from '@editora/light-code-editor';
const guides = new ActiveLineAndIndentGuidesExtension({
activeLine: true,
indentGuides: true,
});
const editor = createEditor(container, {
extensions: [guides]
});
Notes:
tabSize unless you override guideStepColumns.maxGuideDepth and maxGuideLines keep guide rendering bounded on deeply nested or very large documents.createLanguageServiceExtensionsBuilds a coordinated extension bundle so one adapter config can drive syntax highlighting, diagnostics, completions, formatting, hover tooltips, and code actions together.
import {
createLanguageServiceExtensions,
type CompletionContext,
} from '@editora/light-code-editor';
const languageService = createLanguageServiceExtensions({
languageId: 'html',
highlight: ({ text }) =>
text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'),
diagnostics: async ({ text, abortSignal }) => {
if (abortSignal?.aborted) {
return [];
}
return text.includes('onclick=')
? [{
severity: 'warning',
message: 'Inline handlers need review',
range: {
start: { line: 0, column: 0 },
end: { line: 0, column: 7 },
},
}]
: [];
},
completionProviders: [
(context: CompletionContext) =>
context.prefix.startsWith('di')
? [{ label: 'div', kind: 'tag', insertText: 'div' }]
: [],
],
hover: ({ diagnostics }) =>
diagnostics[0]
? {
title: diagnostics[0].code || diagnostics[0].severity,
content: diagnostics[0].message,
range: diagnostics[0].range,
}
: null,
codeActions: ({ lineText, position }) =>
lineText.includes('onclick=')
? [{
label: 'Remove inline onclick handler',
run: (editor) => {
const start = lineText.indexOf('onclick=');
editor.replace(
{
start: { line: position.line, column: Math.max(0, start - 1) },
end: { line: position.line, column: start + 'onclick=""'.length },
},
'',
);
},
}]
: [],
});
const editor = createEditor(container, {
extensions: languageService.extensions,
});
editor.executeCommand('refreshLanguageDiagnostics');
editor.executeCommand('showCodeActions');
Notes:
{ extensions, languageServiceExtension, syntaxHighlightingExtension, diagnosticsExtension, completionExtension, formattingExtension, hoverCodeActionsExtension }.refreshLanguageDiagnostics when you want an explicit provider refresh in addition to change-triggered updates.showCodeActions or Ctrl/Cmd + . to open code actions at the current cursor location.AbortSignal.CompletionExtension and FormattingExtension config surfaces.BracketMatchingExtensionHighlights matching brackets.
import { BracketMatchingExtension } from '@editora/light-code-editor';
const editor = createEditor(container, {
extensions: [new BracketMatchingExtension()]
});
CodeFoldingExtensionEnables code folding for multi-line bracketed blocks and markup tag regions.
import { CodeFoldingExtension } from '@editora/light-code-editor';
const editor = createEditor(container, {
extensions: [new CodeFoldingExtension()]
});
Create your own extensions by implementing the EditorExtension interface:
import { EditorExtension, EditorAPI } from '@editora/light-code-editor';
class MyExtension implements EditorExtension {
public readonly name = 'my-extension';
setup(editor: EditorAPI): void {
// Initialize your extension
editor.registerCommand('my-command', () => {
console.log('My command executed!');
});
}
destroy(): void {
// Cleanup
}
}
The core editor always registers:
undoredoinsertTabsaveExtensions add commands on top:
SyntaxHighlightingExtension: setSyntaxLanguageSearchExtension: find, findNext, findPrev, replace, replaceAllDiagnosticsExtension: setDiagnostics, clearDiagnostics, nextDiagnostic, prevDiagnosticCompletionExtension: showCompletions, closeCompletions, nextCompletion, prevCompletion, acceptCompletionFormattingExtension: formatDocument, formatSelectionHoverTooltipAndCodeActionsExtension: showCodeActions, hideHoverTooltipContextMenuExtension: openContextMenu, closeContextMenuEditingCommandsExtension: toggleLineComment, toggleBlockComment, duplicateLine, moveLineUp, moveLineDown, joinLines, goToLine, openGoToLine, closeGoToLineLanguageServiceExtension: refreshLanguageDiagnosticsThemeExtension: setTheme, toggleThemeReadOnlyExtension: setReadOnly, toggleReadOnlyLineNumbersExtension: toggleLineNumbersCodeFoldingExtension: fold, unfold, foldAll, unfoldAllImport the stylesheet once in your app entry or component bundle:
import '@editora/light-code-editor/light-code-editor.css';
The package also keeps @editora/light-code-editor/dist/light-code-editor.css available for compatibility, but the shorter exported path above is the preferred import for consumers.
The current renderer attaches data attributes instead of public class names:
[data-lce-editor-container="true"] - outer editor container[data-editora-editor="true"] - shared scroll wrapper[data-editor-gutter="true"] - line-number gutter[data-editor-line-decorations="true"] - line decoration overlay[data-editor-gutter-decorations="true"] - gutter decoration overlayFor theming, prefer CSS custom properties such as --editor-background, --editor-foreground, --editor-gutter-background, and --editor-gutter-foreground instead of relying on internal selectors.
Stable decoration hook classes:
.lce-decoration-line.lce-decoration-gutter.lce-decoration-line--active.lce-decoration-gutter--errorThe editor follows a modular, extension-first architecture:
EditorCore
├── TextModel (content management)
├── View (DOM rendering)
├── Extension Registry
├── Command System
└── Event System
This library follows the CodeMirror architecture principles and is designed to be maintainable and extensible. When adding features:
MIT License - see LICENSE file for details.
Ajay Kumar ajaykr089@gmail.com
FAQs
Lightweight code editor for React and web apps with syntax highlighting, search/replace, extensions, and enterprise SaaS integration patterns.
We found that @editora/light-code-editor demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
RubyGems and Bundler 4.0.13 introduced an opt-in cooldown feature that delays newly published gems during dependency resolution.

Security News
pnpm 11.5 now recognizes npm staged publish approvals in release metadata, preventing those releases from being mistaken for lower-trust package publishes.

Security News
Federal audit finds NIST lacked a plan to clear the NVD backlog, wasted funds on duplicate work, and delayed use of CISA data.