Markdown Linting and Formatting in VS Code

This module explores markdown linting and formatting in Visual Studio Code using extensions like Markdownlint and YAML Front Matter Lint.

This comprehensive guide explores advanced markdown linting and formatting techniques in VS Code. Learn how to configure global and project-specific settings using markdownlint.json files, understand rule inheritance, manage ignore patterns, and implement professional formatting workflows. Master the integration of Markdownlint and YAML Front Matter Lint extensions for consistent documentation quality across all your projects.


Global Configuration Inheritance

DavidAnson’s Markdownlint VS Code extension enables the use of a markdownlint.json file to define linting rules. To maintain consistency across all projects, this configuration file can be stored in the user’s home directory. Below are the contents of this global configuration file:

 1{
 2  "default": true,
 3  "MD001": true,
 4  "MD003": {
 5    "style": "atx"
 6  },
 7  "MD004": {
 8    "style": "dash"
 9  },
10  "MD005": true,
11  "MD007": {
12    "indent": 2
13  },
14  "MD009": {
15    "br_spaces": 2
16  },
17  "MD010": true,
18  "MD011": true,
19  "MD012": {
20    "maximum": 1
21  },
22  "MD013": false,
23  "MD014": true,
24  "MD018": true,
25  "MD019": true,
26  "MD020": true,
27  "MD021": true,
28  "MD022": true,
29  "MD023": true,
30  "MD024": false,
31  "MD025": true,
32  "MD026": {
33    "punctuation": ":,;!?"
34  },
35  "MD027": true,
36  "MD028": true,
37  "MD029": {
38    "style": "ordered"
39  },
40  "MD030": true,
41  "MD031": true,
42  "MD032": true,
43  "MD033": false,
44  "MD034": true,
45  "MD035": true,
46  "MD036": true,
47  "MD037": true,
48  "MD038": true,
49  "MD039": true,
50  "MD040": true,
51  "MD041": false,
52  "MD042": true,
53  "MD043": false,
54  "MD044": true,
55  "MD045": true,
56  "MD046": {
57    "style": "fenced"
58  },
59  "MD047": true,
60  "MD048": {
61    "style": "backtick"
62  },
63  "MD049": {
64    "style": "underscore"
65  },
66  "MD050": true,
67  "MD051": true,
68  "MD052": true,
69  "MD053": true,
70  "MD059": false
71}

Set Rules

The above modified rules are a combination of default rules and some customizations. These customizations are based on personal preferences and specific project requirements. They are explained below:

  1. MD003: This rule enforces the use of ATX-style headers (using # symbols) instead of Setext-style headers (using = or - underlines). This preference is often due to the cleaner look and easier readability of ATX headers in plain text.
  2. MD004: This rule specifies the use of dashes (-) for unordered list markers instead of asterisks (*) or plus signs (+). Dashes are often preferred for their simplicity and visual clarity.
  3. MD012: This rule limits consecutive blank lines to a maximum of one. This helps maintain a clean and organized appearance in the Markdown files, preventing excessive whitespace.
  4. MD013: This rule is disabled to allow for longer lines without triggering warnings. This can be useful in certain contexts where line length is less critical.
  5. MD026: This rule specifies which punctuation characters are allowed at the end of headers. The chosen characters (:,;!?) are common in titles and headings, ensuring that headers remain clear and concise.
  6. MD029: This rule enforces the use of ordered lists with a consistent style, ensuring that list items are numbered correctly and consistently.
  7. MD033: This rule is disabled to allow for raw HTML in Markdown files. This can be useful for embedding custom HTML elements that are not natively supported by Markdown.
  8. MD041: This rule is disabled to allow for flexibility in header levels, which can be useful in certain document structures where strict header hierarchy is not necessary.
  9. MD043: This rule is disabled to allow for flexibility in link text, which can be useful in certain contexts where link text may not follow strict conventions.
  10. MD046: This rule enforces the use of fenced code blocks (using triple backticks) instead of indented code blocks. Fenced code blocks are often preferred for their clarity and ability to specify the programming language for syntax highlighting.
  11. MD048: This rule enforces the use of backticks for inline code spans instead of other characters. Backticks are the standard way to denote inline code in Markdown.
  12. MD049: This rule enforces the use of underscores for emphasis instead of asterisks. Underscores can provide a cleaner look in certain contexts, especially when combined with other formatting.

The above rules are applied during the linting and formatting of Markdown files. To utilize this file globally, add its reference to the user’s settings.json file, making these settings available to every project. The settings.json file contains the following entries relevant to Markdown linting:

1// MARKDOWNLINT CONFIGURATION
2// =========================================================================
3"markdownlint.config": {
4  "extends": "/home/ag-sayyed/.markdownlint.json",
5  "defaultRules": {
6    // Add any rules you want to disable globally here
7    // "MD013": false,
8  }
9}

Configuration Options

When global settings are configured, you have several options for project-specific implementation:

  1. Inherit Global Settings: Use global settings without modification
  2. Override Global Settings: Create project-specific configurations
  3. Extend Global Settings: Add additional rules while maintaining global baseline

Your local project will automatically inherit the global settings. You can only add ignore patterns either in a markdownlint-cli2.jsonc file or in the project’s .vscode/settings.json file:

 1// In markdownlint-cli2.jsonc file
 2{
 3  "ignores": [
 4    "**/node_modules/**",
 5    "**/dist/**",
 6    "**/vendor/**",
 7    "**/.git/**",
 8    "**/.vscode/**",
 9    "**/scripts/test-fixtures/*.md"
10  ]
11}
12
13// OR in .vscode/settings.json file
14{
15  "markdownlint.ignore": [
16    "scripts/test-fixtures/**",
17    "node_modules/**",
18    ".git/**"
19  ]
20}

Overriding Global Settings

To override global settings, create project-specific rules or configurations in a local file. This approach allows customization of linting and formatting behavior for individual projects without affecting global settings. To implement this:

  1. Create a .markdownlint.jsonc file in your project root
  2. Configure the settings to extend the global file and override specific rules as needed
1{
2  "extends": "/home/ag-sayyed/.markdownlint.json",
3  "MD001": false // Disable heading level rule for this project
4}

Identifying Linting Issues

Content containing Markdown formatting issues will be displayed in the Problems tab of the VS Code panel and highlighted directly in the editor using colored squiggly lines.

Visual demonstration of markdown linting issues with colored indicators

Markdown content displaying linting issues from multiple extensions in VS Code

The red indicators are generated by the YAML Front Matter Lint extension, while the green indicators are produced by the Markdownlint extension. These issues are detected because the project is reading rules from the configuration file.

Understanding Linting Issues

VS Code displays linting issues in the bottom panel’s Problems tab. The issues are explained in detail as shown below:

Detailed explanation of linting issues in VS Code Problems panel

Comprehensive linting issues breakdown by installed extensions

Configuring Ignore Patterns and Files

To specify files and folders to ignore, create a new file named .markdownlint-cli2.jsonc in your project root directory. Add file patterns using the correct glob syntax **/<foldername>/**. For example, the following entry will successfully ignore all Markdown files from the specified folder /scripts/test-fixtures/*.md:

1// File: .markdownlint-cli2.jsonc
2{
3  "ignores": [
4    "**/node_modules/**",
5    "**/dist/**",
6    "**/build/**",
7    "**/scripts/test-fixtures/**"
8  ]
9}

Visual Indicators:

  • Linting issues are highlighted with green squiggly lines in the editor
  • Issue count is displayed on the status bar in the bottom-left corner with a triangle icon
  • Clicking the triangle icon opens the Problems tab in the panel

Testing Formatting Functionality

Create a sample Markdown file with unformatted content and test the formatting using all three available methods:

  1. Focus Change: Move focus away from the file and return
  2. Manual Save: Use Ctrl+S to save the file
  3. Context Menu: Right-click and select Format Document

All methods should format the file according to the default settings defined in the global configuration.


Current Configuration Summary

Key Observations

  1. Minimal Configuration: No local configuration files are required except for a single file following the markdownlint-cli2 format to ignore specific files using the ignores entry.

  2. Automatic Formatting: Formatting is automatically triggered on focus change and save events as configured in global settings.

  3. Extension-Based Processing: Only VS Code extensions are used for formatting; no project-specific formatters are installed.

  4. Independent Extension Operation:

    • YAML frontmatter issues are handled by the YAML Front Matter Lint extension
    • Markdown content issues are managed by the Markdownlint extension
    • Both extensions operate independently without conflicts
  5. Configuration Flexibility: Both extensions support their own configuration files when present in the project root.

  6. Multiple Formatting Options: Formatting is available through context menu Format Document option as well as automatic triggers.

  7. Prettier Integration: No Prettier configuration file is currently used.

  8. Partial Issue Resolution: Not all linting or formatting issues are automatically fixed.

  9. Clean Project Settings: No project-level settings exist in .vscode/settings.json or workspace files.

Project Settings Configuration

At this stage, the .vscode/settings.json file remains minimal, containing only intentional color customizations. No project-specific linting or formatting settings are present, ensuring that global/user settings are applied correctly.

1{
2  "workbench.colorCustomizations": {
3    "activityBar.background": "#0C0C9A",
4    "titleBar.activeBackground": "#1111D8",
5    "titleBar.activeForeground": "#FBFBFF"
6  }
7}
1{
2  "editor.formatOnSaveMode": "file",
3  "workbench.colorCustomizations": {
4    "activityBar.background": "#0C0C9A",
5    "titleBar.activeBackground": "#1111D8",
6    "titleBar.activeForeground": "#FBFBFF"
7  }
8}

Limiting Factors

Markdownlint-cli2 cannot automatically fix heading levels or reformat your Markdown content. It’s a linter, not a formatter.

  • What markdownlint-cli2 does:

    • It detects issues like incorrect heading levels (e.g., starting with # instead of ##) using rules like MD001 (heading levels should increment by one).
    • It reports those issues in a structured format (JSON, pretty, SARIF, etc.).
    • It helps you enforce consistency and style across your Markdown files.
  • What it does not do:

    • It does not auto-correct or reformat your Markdown files.
    • It won’t rewrite headings, fix spacing, or adjust indentation.

For example, if you have a heading that should be ## instead of #, markdownlint-cli2 will flag it as an issue, but you’ll need to manually change it in your file. On the other hand if the same heading has another issue like missing space after #Heading, it will be automatically fixed as # Heading on save or focus change or on formatting either from context menu or running a CLI tool.


Noisy Linting Markers

  • By default, linting markers can be quite noisy while typing because they update in real-time. This can be distracting, especially if you’re making a lot of changes.
  • Avoid them by adding the following setting to your global settings.json file:
1{
2  "markdownlint.run": "onSave",
3  "editor.codeActionsOnSave": {
4    "source.fixAll.markdownlint": "explicit"
5  }
6}

This configuration ensures that linting only occurs when you save the file and all fixable issues are automatically resolved on explicit save actions. If you want to change this setting so all errors are fixed on every save, change "explicit" to "always".


Conclusion

This module demonstrates the effective implementation of Markdown linting and formatting in VS Code through a combination of global configurations and minimal project-specific settings. The approach ensures:

  • Consistency across all projects through global rule inheritance
  • Flexibility to override settings when needed
  • Efficiency with out-of-the-box functionality
  • Professional documentation quality through automated linting

The configuration strikes an optimal balance between comprehensive linting coverage and ease of implementation, making it suitable for both individual developers and team environments.


FAQs