Fold Markdown headings

Hello folks!

I might be wrong, but I noticed that Markdown headings are not recognized as foldable by default.

Example link: Try CodeMirror

While in CodeMirror5 examples, I found that headings are correctly shown as foldable.

Example link: CodeMirror: Code Folding Demo

Is this an intended change or am I missing something obvious? If it’s not desperately hard to achieve the goal, I would like to learn a bit more about it.

Sorry if I missed something before creating this topic.

Update, I’ve made a naive approach by relying on the foldService facet:

import { foldService } from "@codemirror/language";

export const makeHeadingsFoldable = foldService.of((state, from, to) => {
  const regex = /^ *(#{1,6}) /gm;
  const match = regex.exec(state.doc.sliceString(from, to));
  if (match === null || to === state.doc.length) {
    return null;

  // The heading level we are looking for
  const level = match[1].length;
  const lines = state.doc.lines;

  for (let index = state.doc.lineAt(to).number; index <= lines; ++index) {
    const line = state.doc.line(index);
    const match = regex.exec(line.text);

    // E.g., we can fold text between two "##" headings, or from "##" to "#",
    // deeper headings like "###" will be collapsed.
    if (match !== null && match[1].length <= level) {
      return { from: to, to: line.from - 1 };

  // The entire range after the current line can be collapsed
  return { from: to, to: state.doc.length };

I am not sure if this is the recommended direction, and if there’s a way to leverage the Markdown parser instead.


This is a good idea. The patch below adds it to lang-markdown

@marijn Thank you for making this built-in! Also, thanks for providing such a great example.