# Using the DBX Query Editor with CodeMirror 6: Implementation Guide

> Integrate DBX Query Editor with CodeMirror 6 for a powerful SQL editing experience. Learn implementation in this Vue 3 guide. Features lazy loading, themes and completions.

- Repository: [skyler/dbx](https://github.com/t8y2/dbx)
- Tags: how-to-guide
- Published: 2026-07-02

---

**DBX's Query Editor is a Vue 3 component that wraps CodeMirror 6 to provide a full-featured SQL editing experience with lazy-loaded modules, dynamic theming, and extensible completion engines.**

The DBX query editor leverages CodeMirror 6 to deliver a high-performance SQL editing environment within the t8y2/dbx repository. This implementation demonstrates how to integrate CodeMirror's modular architecture with application-specific features like dialect-aware syntax highlighting, semantic diagnostics, and customizable keyboard shortcuts while maintaining minimal bundle sizes through dynamic imports.

## Architecture Overview

The editor architecture separates concerns between the Vue UI layer and CodeMirror's state management system. At [`apps/desktop/src/components/editor/QueryEditor.vue`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/components/editor/QueryEditor.vue), the component hosts a CodeMirror `EditorView` instance that communicates with the rest of the application through a rich event system.

The initialization flow follows this pattern:

1. **Lazy Module Loading** – The `loadCodeMirrorModules()` function dynamically imports `@codemirror/view`, `@codemirror/state`, `@codemirror/autocomplete`, and related packages only when the component mounts
2. **Extension Assembly** – Extensions are composed from dialect configurations, themes, keymaps, and diagnostic providers
3. **State Persistence** – CodeMirror `Compartment` objects enable dynamic reconfiguration without destroying the editor state
4. **Event Wiring** – User actions emit Vue events (`execute`, `save`, `clickTable`) that parent components consume

## Core Components

### Vue Wrapper and Lifecycle

The [`QueryEditor.vue`](https://github.com/t8y2/dbx/blob/main/QueryEditor.vue) component manages the editor's lifecycle through standard Vue hooks. During `onMounted`, it calls `init()` which creates the `EditorView` instance inside a container div.

```vue
<template>
  <div ref="editorContainer" class="query-editor" />
</template>

```

The component accepts props including `modelValue`, `dialect`, `readOnly`, and `connectionId`, emitting structured events when users execute queries or interact with database objects. When the component unmounts, `onBeforeUnmount` properly destroys the CodeMirror view to prevent memory leaks.

### SQL Dialect Handling

Language support is implemented in [`apps/desktop/src/lib/codemirrorSqlDialect.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/lib/codemirrorSqlDialect.ts). The `createDbxCodeMirrorSqlDialect()` function returns a `SQLDialect` configuration for MySQL, PostgreSQL, or SQL Server by loading `@codemirror/lang-sql` and selecting the appropriate language class:

```typescript
import { createDbxCodeMirrorSqlDialect } '@/lib/codemirrorSqlDialect'

const dialect = createDbxCodeMirrorSqlDialect('postgres')
// Returns CodeMirror language extension with PostgreSQL-specific tokenization

```

### Theme and Font Styling

Dynamic theming is handled in [`apps/desktop/src/lib/editorThemes.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/lib/editorThemes.ts). The `editorFontTheme()` and `buildEditorFontThemeRules()` functions translate DBX's theme settings into CodeMirror `EditorView.theme` extensions:

```typescript
import { loadEditorTheme } from '@/lib/editorThemes'

const themeExtension = await loadEditorTheme('vscodeDark')
// Applies to fontThemeComp.reconfigure(themeExtension) for live updates

```

Compartments allow font sizes, families, and color palettes to change without losing cursor position or edit history.

### Shortcut Mapping

Keyboard shortcuts are normalized in [`apps/desktop/src/lib/shortcutRegistry.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/lib/shortcutRegistry.ts). The `shortcutToCodeMirrorKey()` function converts DBX's platform-aware shortcut definitions into CodeMirror-compatible key strings:

```typescript
// Maps { windows: 'Ctrl+Enter', macos: 'Cmd+Enter' } to 'Mod-Enter'
const cmKey = shortcutToCodeMirrorKey(shortcutDefinition)

```

These keys are bound through `runKeymapExtension()` and integrated with the editor's command palette.

## Advanced Features

### Autocomplete and Diagnostics

Context-aware completions are generated in [`apps/desktop/src/lib/sqlCompletion.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/lib/sqlCompletion.ts) via `buildSqlCompletionItemsFromContext()`, which queries the DBX metadata cache for tables, columns, and functions. Semantic diagnostics operate through [`apps/desktop/src/lib/sqlSemanticDiagnostics.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/lib/sqlSemanticDiagnostics.ts), running debounced checks via `scheduleSemanticDiagnostics()` and displaying results as CodeMirror decorations.

Hover tooltips are resolved through `resolveSqlHoverTooltip()`, which inspects the connection store to provide schema metadata when users hover over table or column references.

### Search and Replace

The search interface is implemented in [`apps/desktop/src/components/editor/EditorSearchPanel.vue`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/components/editor/EditorSearchPanel.vue). This Vue overlay integrates with CodeMirror's `@codemirror/search` extension (`cmSearch`) to provide live find/replace functionality with result highlighting.

### SQL Formatting

Code formatting is handled by [`apps/desktop/src/lib/sqlFormatter.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/lib/sqlFormatter.ts). The `formatSqlText()` function accepts SQL text and a dialect identifier, returning formatted code that respects the selected database syntax:

```typescript
import { formatSqlText } from '@/lib/sqlFormatter'
import type { SqlFormatDialect } from '@/types/database'

const formatted = await formatSqlText(rawSql, 'postgres' as SqlFormatDialect)

```

The editor binds this to `Ctrl+Shift+F` (or user-defined shortcuts) through the command palette.

## Implementation Examples

### Embedding the Editor

Include the component in custom views with full event binding:

```vue
<template>
  <QueryEditor
    v-model="sql"
    :dialect="dialect"
    :connection-id="connId"
    :database="dbName"
    @execute="runQuery"
    @save="saveSnippet"
  />
</template>

<script setup lang="ts">
import QueryEditor from '@/components/editor/QueryEditor.vue'
import { ref } from 'vue'

const sql = ref('SELECT * FROM users;')
const dialect = ref<'mysql' | 'postgres' | 'sqlserver'>('postgres')
const connId = 'c12345'
const dbName = 'mydb'

function runQuery (payload: { fullSql: string, selectedSql?: string, cursorPos: number }) {
  console.log('Executing:', payload.selectedSql || payload.fullSql)
}

function saveSnippet () {
  // Persist sql.value to storage
}
</script>

```

### Programmatic Theme Changes

Switch themes without reinitializing the editor:

```typescript
import { loadEditorTheme } from '@/lib/editorThemes'

async function applyDarkTheme () {
  const theme = await loadEditorTheme('vscodeDark')
  // Settings store triggers fontThemeComp.reconfigure(theme)
  // Editor updates immediately while preserving scroll position
}

```

### Adding Custom Shortcuts

Extend the editor's command palette through the settings store:

```typescript
import { settingsStore } from '@/stores/settingsStore'

settingsStore.editorSettings.shortcuts.push({
  id: 'customRun',
  keys: { 
    windows: 'Ctrl+Enter', 
    macos: 'Cmd+Enter', 
    linux: 'Ctrl+Enter' 
  },
  // Handler registered in shortcutRegistry
})

```

## Summary

- **DBX's Query Editor** wraps CodeMirror 6 in a Vue 3 component at [`apps/desktop/src/components/editor/QueryEditor.vue`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/components/editor/QueryEditor.vue)
- **Lazy loading** via `loadCodeMirrorModules()` keeps initial bundle sizes minimal while supporting full IDE features
- **Dialect support** for MySQL, PostgreSQL, and SQL Server is configured through `createDbxCodeMirrorSqlDialect()`
- **Dynamic configuration** uses CodeMirror `Compartment` objects to update themes, fonts, and keymaps without state loss
- **Extensible architecture** separates concerns between completion engines ([`sqlCompletion.ts`](https://github.com/t8y2/dbx/blob/main/sqlCompletion.ts)), diagnostics ([`sqlSemanticDiagnostics.ts`](https://github.com/t8y2/dbx/blob/main/sqlSemanticDiagnostics.ts)), and formatting ([`sqlFormatter.ts`](https://github.com/t8y2/dbx/blob/main/sqlFormatter.ts))

## Frequently Asked Questions

### How does DBX handle different SQL dialects in the same editor?

The `createDbxCodeMirrorSqlDialect()` function in [`apps/desktop/src/lib/codemirrorSqlDialect.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/lib/codemirrorSqlDialect.ts) dynamically imports `@codemirror/lang-sql` and instantiates the appropriate language class—`MySQL`, `PostgreSQL`, or `MSSQL`—based on the `dialect` prop passed to the QueryEditor component. This allows the editor to provide accurate syntax highlighting and tokenization for the specific database backend.

### Can I customize the keyboard shortcuts in the DBX query editor?

Yes. Shortcuts are managed through [`apps/desktop/src/lib/shortcutRegistry.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/lib/shortcutRegistry.ts), which normalizes platform-specific key combinations using `shortcutToCodeMirrorKey()`. You can add custom shortcuts by modifying the `settingsStore.editorSettings.shortcuts` array; changes are applied immediately via the `runKeymapExtension()` function without requiring a page reload.

### What happens to my editor state when I change themes or settings?

DBX uses CodeMirror 6's `Compartment` objects to isolate configurable extensions like themes and fonts. When settings change, the relevant compartment is reconfigured (e.g., `fontThemeComp.reconfigure(...)`), which updates the editor's appearance while preserving the document content, cursor position, and selection history.

### How does the editor provide autocomplete suggestions for my database schema?

The completion system in [`apps/desktop/src/lib/sqlCompletion.ts`](https://github.com/t8y2/dbx/blob/main/apps/desktop/src/lib/sqlCompletion.ts) builds context-aware suggestions through `buildSqlCompletionItemsFromContext()`. This function queries the DBX metadata cache (managed via `connectionStore`) to retrieve table names, column definitions, and function signatures specific to the active connection, then formats them as CodeMirror completion items with documentation and type information.