Skip to content

ckant/codemirror-markdown-tables

Repository files navigation

logo

CodeMirror extension that turns Markdown tables into interactive components

View live demo

Package Downloads MIT License

FeaturesInstallationUsageCustomizationCreditsLicense

preview

Features

Table editor

A powerful table component that seamlessly integrates with CodeMirror

  • Renders Markdown table text as interactive HTML tables
  • Autoformats and prettifies Markdown tables while editing
  • Renders custom styles and custom themes in code and/or CSS
  • Renders cells with multi-line text
  • Autocorrects line breaks around tables while editing to keep them separate from surrounding text
  • Integrates with native CodeMirror undo history
  • Integrates with native CodeMirror search
  • Implements touch-friendly controls and editing for mobile browsers
  • Autoinserts line breaks around pasted tables when necessary to keep them on their own lines
  • Autoescapes pipe characters in cell text

Interactions

Type multi-line text
  • Create line breaks with Shift+Enter (inserts a <br>)
Navigate around the table
  • Move around the table with Up,Down,Left,Right
  • Move to the next cell with Tab
    • Append a new row by moving past the last cell
  • Move to the previous cell with Shift+Tab
    • Prepend a new row by moving before the first cell
  • Move to the cell below with Enter
    • Append a new row by moving past the last row
Select cells
  • Select a group of cells by Clicking and Dragging
    • Scroll the table by Dragging past the editor edge
  • Resize the cell selection by Shift+Clicking and Dragging
  • Resize the cell selection with Shift+Up,Shift+Down,Shift+Left,Shift+Right
Clear cells
  • Clear selected cells with Backspace,Delete
  • Delete selected empty rows/columns with Backspace,Delete
Copy/paste cells
  • Copy selected cells as a Markdown table with Ctrl+C/Cmd+C
  • Cut selected cells as a Markdown table with Ctrl+X/Cmd+X
  • Paste a Markdown table into selected cells with Ctrl+V/Cmd+V
    • Select excess cells to duplicate the pasted Markdown table across the extra cells
Rearrange a row/column
  • Move row/column by Clicking Row/Column and Dragging to a new location
    • Scroll the table by Dragging past the editor edge
Insert rows/columns
  • Insert a row by Clicking Row Border
  • Insert one or more rows by Clicking Row Border and Dragging Down
  • Insert a column by Clicking Column Border
  • Insert one or more columns by Clicking Column Border and Dragging Right
Delete empty rows/columns
  • Delete one or more empty rows by Clicking Row Border and Dragging Up
  • Delete one or more empty columns by Clicking Column Border and Dragging Left
Append rows/columns
  • Append a row by Clicking Table Bottom Button
  • Append one or more rows by Clicking Table Bottom Button and Dragging Down
  • Append a column by Clicking Table Right Button
  • Append one or more columns by Clicking Table Right Button and Dragging Right
  • Append a row and column by Clicking Table Bottom-Right Button
  • Append one or more rows and columns by Clicking Table Bottom-Right Button and Dragging Down-Right
Trim empty rows/columns
  • Trim one or more empty rows by Clicking Table Bottom Button and Dragging Up
  • Trim one or more empty columns by Clicking Table Right Button and Dragging Left
  • Trim one or more empty rows and columns by Clicking Table Bottom-Right Button and Dragging Up-Left
Execute actions on a row/column
  • Open row/column menu by Clicking Row/Column
    • Sort by column
    • Align a column to left, center, or right
    • Unalign a column
    • Add a row/column
    • Move a row/column
    • Duplicate a row/column
    • Clear a row/column
    • Delete a row/column

Autocompletion

A convenient autocomplete menu for creating tables

  • Pops up a CodeMirror autocompletion menu after typing | on an empty line
  • Displays a customizable list of table size options

Command

A command that smartly inserts a new Markdown table

  • Inserts an empty Markdown table at the cursor or replaces the current selection
  • Adds line breaks around table when necessary to prevent overlap with surrounding text

Installation

npm install codemirror-markdown-tables

Usage

Add the core extension (required)

import { EditorView } from "@codemirror/view"

import { markdownTables } from "codemirror-markdown-tables"

// Add Markdown tables extension to CodeMirror
new EditorView({
  extensions: [markdownTables()],
})

Add an extension that autocompletes a table after typing | (optional)

import { autocompletion } from "@codemirror/autocomplete"
import { markdown, markdownLanguage } from "@codemirror/lang-markdown"
import { EditorView } from "@codemirror/view"

import { markdownTableAutocompleter } from "codemirror-markdown-tables"

// Create markdown language with GitHub-flavored Markdown support
const markdownLanguageSupport = markdown({ base: markdownLanguage })

// Create Markdown tables autocomplete extension (merges with other Markdown autocomplete extensions)
const markdownTableAutocompletion = markdownLanguageSupport.language.data.of({
  autocomplete: markdownTableAutocompleter(),
})

// Add all extensions to CodeMirror
new EditorView({
  extensions: [autocompletion(), markdownLanguageSupport, markdownTableAutocompletion],
})

Add a keyboard shortcut that inserts a Markdown table (optional)

import { EditorView, keymap } from "@codemirror/view"

import { insertEmptyMarkdownTable } from "codemirror-markdown-tables"

// Create key binding that inserts a 2x2 table
const insertTableKeyBinding = {
  key: "Alt-Mod-t",
  run: insertEmptyMarkdownTable(),
}

// Wrap the key binding inside a keymap and add the extension to CodeMirror
new EditorView({
  extensions: keymap.of([insertTableKeyBinding]),
})

Customization

Core config

Optional config passed into the markdownTables() function to customize the core extension

Property Values Default (when omitted or undefined) Description
theme TableTheme,
{ light: TableTheme; dark: TableTheme }
{ light: TableTheme.light, dark: TableTheme.dark } Color scheme for the table

When set to a light and dark theme, the theme adjusts based on the CodeMirror light and dark mode configuration (not CSS prefers-color-scheme)

When set to a single theme, the theme applies in both modes (i.e. theme: SomeTheme is equivalent to theme: { light: SomeTheme, dark: SomeTheme })
style TableStyle TableStyle.default Fonts and other styles for the table
selectionType "codemirror", "native" "codemirror" Text cursor and selection implementation for the table cell editor

When set to "codemirror", the editor uses CodeMirror's implementation
Essentially, the CodeMirror editor embedded inside cells enables the drawSelection extension along with some CSS that hides the browser's native cursor and selection

When set to native, the editor uses the browser's implementation

Specify native only if drawSelection isn't enabled in the root CodeMirror editor (it's enabled by default with basicSetup and minimalSetup)
handlePosition "outside", "inside" "outside" Position of the row and column header grips

When set to "outside", handles appear beyond the top/left edge of the table
This requires a sufficient left margin to keep the table edge aligned with the root CodeMirror editor edge, but it's much easier to click and drag the handles, especially on mobile

When set to "inside", handles appear on the top/left table border itself
This requires no extra left margin, but it's difficult to click and drag the handles, especially on mobile
lineWrapping "wrap"", "nowrap" "wrap" Wrapping mode of the table

When set to "wrap", wraps long table cell text
Essentially, the CodeMirror editor embedded inside cells enables the lineWrapping extension along with the CSS "word-break": "normal", "overflow-wrap": "break-word"

When set to "nowrap", the editor does not wrap long table cell text
The editor sets the CSS to white-space: "pre"
extensions Extension[] [] Extensions for the table cell editor

The CodeMirror editor embedded inside cells (not the root CodeMirror editor) enables the given extensions

The table cell editor doesn't automatically inherit root CodeMirror editor extensions
Instead, specify basic editor extensions like highlightWhitespace here to enable them inside cells

Keyboard shortcuts specified here execute actions on the CodeMirror editor embedded inside cells, rather than the root CodeMirror editor
They operate on the text inside the cell in isolation, rather than the text of the document as a whole

Specify KeyBindings from defaultKeymap or similar here to enable basic shortcuts inside the cell editor
defaultKeymap defines shortcuts like Ctrl+A/Cmd+A which should select all the cell text rather than all the document text

Conversely, specify KeyBindings from historyKeymap and searchKeymap in globalKeyBindings instead, since these keyboard shortcuts operate on the root CodeMirror editor and the document as a whole
markdownConfig MarkdownConfig {} Markdown language configuration for the table cell editor

The CodeMirror editor embedded inside cells calls the markdown() function in @codemirror/lang-markdown with the specified options

The table cell editor doesn't automatically inherit the root CodeMirror Markdown language configuration

See @codemirror/lang-markdown for descriptions
globalKeyBindings KeyBinding[] [] Keyboard shortcuts for the table cell editor that delegate to the root CodeMirror editor

Keyboard shortcuts specified here execute actions on the root CodeMirror editor, rather than the CodeMirror editor embedded inside cells
They operate on the text of the document as a whole, rather than the text inside the cell in isolation

Specify KeyBindings from historyKeymap or similar here to enable history shortcuts while inside the cell editor
historyKeymap defines keyboard shortcuts like Ctrl+Z/Cmd+Z which should undo across the document text rather than just the cell text
Another example is searchKeymap which defines keyboard shortcuts that should search across the entire document text rather than just the cell text

Conversely, specify KeyBindings from defaultKeymap in extensions instead, since these keyboard shortcuts operate on the CodeMirror editor embedded inside cells and the text inside the cell in isolation

Table theme

A theme is a collection of properties that define the CSS color scheme

Built-in themes
Name Description
TableTheme.light Basic light theme that works well with the CodeMirror default theme
TableTheme.dark Basic dark theme
TableTheme.githubLight Theme based on table colors in GitHub's light theme
TableTheme.githubDark Theme based on table colors in GitHub's dark theme
TableTheme.githubSoftDark Theme based on table colors in GitHub's soft dark theme
TableTheme.oneDark Dark theme that works well with @codemirror/theme-one-dark
Custom themes

Create custom themes in code or override theme properties in CSS

In code
import { TableTheme } from "codemirror-markdown-tables"

const customDarkTheme = TableTheme.dark.with({
  "--tbl-theme-header-row-background": "gray",
  "--tbl-theme-outline-color": "green",
})
In CSS
:root {
  --tbl-theme-header-row-background: gray;
  --tbl-theme-outline-color: green;
}
Properties

Theme properties correspond directly to CSS variables of the same name defined in :root scope

Property Values Description
--tbl-theme-row-background CSS color Background color of all cells, unless overriden by other *-row-background properties
--tbl-theme-header-row-background CSS color Background color of the cells in the header row
--tbl-theme-even-row-background CSS color Background color of the cells in even rows
--tbl-theme-odd-row-background CSS color Background color of the cells in odd rows (except the header row)
--tbl-theme-border-color CSS color Color of borders
--tbl-theme-border-hover-color CSS color Color of a hovered border
--tbl-theme-border-active-color CSS color Color of a clicked border
--tbl-theme-outline-color CSS color Color of the outline around selected cells
--tbl-theme-text-color CSS color Color of text
--tbl-theme-menu-border-color CSS color Color of menu borders
--tbl-theme-menu-background CSS color Background color of menu items
--tbl-theme-menu-hover-background CSS color Background color of a hovered menu item
--tbl-theme-menu-text-color CSS color Color of menu item text
--tbl-theme-menu-hover-text-color CSS color Color of hovered menu item text
--tbl-theme-select-all-focus-overlay CSS color Color of the layer overlaid on table when a Select All takes place and the editor has focus

The overlay shows as an alpha layer above the table whereas CodeMirror places its default selection background behind editor text
So specify an alpha overlay color that, when mixed with the table background color, mimics the opaque CodeMirror selection background color
--tbl-theme-select-all-blur-overlay CSS color Color of the layer overlaid on table when a Select All takes place and the editor doesn't have focus

The overlay shows as an alpha layer above the table whereas CodeMirror places its default selection background behind editor text
So specify an alpha overlay color that, when mixed with the table background color, mimics the opaque CodeMirror selection background color

Table style

A style is a collection of properties that define fonts and other CSS styles

Built-in styles
Name Values Description
TableStyle.default { "--tbl-style-font-family": "system-ui", "--tbl-style-font-size": "inherit", "--tbl-style-menu-font-family": "system-ui", "--tbl-style-menu-font-size": "inherit", "--tbl-style-default-header-alignment": "left", } Basic style with sensible defaults
Custom styles

Create custom styles in code or override style properties in CSS

In code
import { TableStyle } from "codemirror-markdown-tables"

const customStyle = TableStyle.default.with({
  "--tbl-style-font-family": '"Comic Sans", sans-serif',
  "--tbl-style-font-size": "16px",
})
In CSS
:root {
  --tbl-style-font-family: "Comic Sans", sans-serif;
  --tbl-style-font-size: 16px;
}
Properties

Style properties correspond directly to CSS variables of the same name defined in :root scope

Property Values Description
--tbl-style-font-family CSS font-family Font family of text
--tbl-style-font-size CSS font-size Font size of text
--tbl-style-menu-font-family CSS font-family Font family of menu item text
--tbl-style-menu-font-size CSS font-size Font size of menu item text
--tbl-style-default-header-alignment "left", "center", "right" Alignment of text in header cell when its column is otherwise unaligned

Table autocompleter config

Optional config passed into the markdownTableAutocompleter() function to customize the autocompleter

Property Values Default (when omitted or undefined) Description
options { rows: number, cols: number}[] [{ rows: 2, cols: 2 }, { rows: 3, cols: 3 }, { rows: 4, cols: 4 }] Options shown in the autocomplete popup

Insert table command config

Optional config passed into the insertEmptyMarkdownTable() function to customize the insert table command

Property Values Default (when omitted or undefined) Description
size { rows: number, cols: number} { rows: 2, cols: 2 } Size of the inserted table

Examples

Complete, minimal configuration

import { basicSetup } from "codemirror"
import { markdown, markdownLanguage } from "@codemirror/lang-markdown"
import { EditorView, keymap } from "@codemirror/view"

import {
  insertEmptyMarkdownTable,
  markdownTables,
  markdownTableAutocompleter,
} from "codemirror-markdown-tables"

const markdownLanguageSupport = markdown({ base: markdownLanguage })

new EditorView({
  extensions: [
    basicSetup,
    markdownLanguageSupport,
    markdownLanguageSupport.language.data.of({ autocomplete: markdownTableAutocompleter() }),
    markdownTables(),
    keymap.of([{ key: "Alt-Mod-t", run: insertEmptyMarkdownTable({ rows: 2, cols: 2 }) }]),
  ],
  parent: document.body,
})

Complete, extensive configuration

import { basicSetup } from "codemirror"
import { defaultKeymap, historyKeymap } from "@codemirror/commands"
import { markdown, markdownLanguage } from "@codemirror/lang-markdown"
import { searchKeymap } from "@codemirror/search"
import { EditorView, highlightSpecialChars, keymap } from "@codemirror/view"
import { Autolink, Emoji, Strikethrough, Subscript, Superscript } from "@lezer/markdown"

import {
  insertEmptyMarkdownTable,
  markdownTables,
  markdownTableAutocompleter,
  TableStyle,
  TableTheme,
} from "codemirror-markdown-tables"

const markdownLanguageSupport = markdown({ base: markdownLanguage })

new EditorView({
  extensions: [
    basicSetup,
    markdownLanguageSupport,
    markdownLanguageSupport.language.data.of({
      autocomplete: markdownTableAutocompleter({
        options: [
          { rows: 2, cols: 2 },
          { rows: 3, cols: 3 },
        ],
      }),
    }),
    markdownTables({
      theme: {
        light: TableTheme.light,
        dark: TableTheme.dark.with({
          "--tbl-theme-row-background": "#000",
          "--tbl-theme-text-color": "#ccc",
          "--tbl-theme-menu-background": "#000",
          "--tbl-theme-menu-text-color": "#ccc",
        }),
      },
      style: TableStyle.default.with({
        "--tbl-style-font-size": "16px",
        "--tbl-style-menu-font-size": "14px",
        "--tbl-style-default-header-alignment": "center",
      }),
      markdownConfig: {
        extensions: [Strikethrough, Autolink, Subscript, Superscript, Emoji],
      },
      extensions: [highlightSpecialChars(), keymap.of(defaultKeymap)],
      globalKeyBindings: [...historyKeymap, ...searchKeymap],
    }),
    keymap.of([{ key: "Alt-Mod-t", run: insertEmptyMarkdownTable({ rows: 3, cols: 3 }) }]),
  ],
  parent: document.body,
})

Light and dark mode CSS overrides

/* Only applies in CodeMirror light mode */
:root:has([data-tbl-theme-mode="light"]) {
  --tbl-theme-row-background: gray;
}

/* Only applies in CodeMirror dark mode */
:root:has([data-tbl-theme-mode="dark"]) {
  --tbl-theme-row-background: #000;
}

Credits

License

Copyright © 2026 Chris Kant.
This project is MIT licensed

About

CodeMirror extension that turns Markdown tables into interactive components

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published