ZetCode

Java Flexmark

last modified July 4, 2026

In this article we show how to work with the Flexmark library which is used to parse and render Markdown in Java. We provide several code examples to work with Markdown in Java.

Markdown is a lightweight markup language with plain text formatting syntax. It is widely used for documentation, readme files, blog posts, and note-taking. Flexmark implements the CommonMark specification, a strongly defined, highly compatible standard that resolves ambiguities found in the original Markdown specification.

Flexmark also supports GitHub-Flavored Markdown (GFM) extensions including tables, task lists, and strikethrough, making it suitable for rendering the same Markdown that developers use on platforms like GitHub.

Flexmark library

Flexmark is a Java library for parsing and rendering Markdown according to the CommonMark specification. It is highly extensible with plugins for tables, task lists, strikethrough, footnotes, and many more features.

<dependencies>
    <dependency>
        <groupId>com.vladsch.flexmark</groupId>
        <artifactId>flexmark</artifactId>
        <version>0.64.8</version>
    </dependency>
    <dependency>
        <groupId>com.vladsch.flexmark</groupId>
        <artifactId>flexmark-ext-tables</artifactId>
        <version>0.64.8</version>
    </dependency>
    <dependency>
        <groupId>com.vladsch.flexmark</groupId>
        <artifactId>flexmark-ext-gfm-tasklist</artifactId>
        <version>0.64.8</version>
    </dependency>
    <dependency>
        <groupId>com.vladsch.flexmark</groupId>
        <artifactId>flexmark-ext-gfm-strikethrough</artifactId>
        <version>0.64.8</version>
    </dependency>
</dependencies>

These are the Maven dependencies for Flexmark, including the core library and extensions for tables, task lists, and strikethrough.

Parsing Markdown

The first example shows how to parse a Markdown string into an abstract syntax tree (AST).

Main.java
import com.vladsch.flexmark.parser.Parser;

void main() {

    var markdown = """
        # Hello, CommonMark!

        This is a **Markdown** document with a [link](https://commonmark.org).
        """;

    var parser = Parser.builder().build();
    var document = parser.parse(markdown);

    System.out.println(document);
}

The example parses a Markdown string using the default parser and prints the resulting AST.

var markdown = """
    # Hello, CommonMark!

    This is a **Markdown** document with a [link](https://commonmark.org).
    """;

A Markdown string is defined using a Java text block. The string contains a heading, a paragraph with bold text, and a link.

var parser = Parser.builder().build();
var document = parser.parse(markdown);

The Parser is built using the builder pattern. The parse method converts the Markdown string into a Document AST node.

$ java -cp "lib/*" Main.java
Document{}

The output is Document{}. The Document class does not override toString, so it falls back to the default Object.toString implementation, which prints the class name and an empty braces pair. The parsed content is not lost — the Document object contains a full tree of AST nodes representing the heading, paragraph, bold text, and link.

To actually see the result, you need to pass the document to an HtmlRenderer or traverse the node tree manually. We cover rendering to HTML in the next section.

Rendering to HTML

The most common use case is converting Markdown to HTML.

Main.java
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;

void main() {

    var markdown = """
        # Features

        Flexmark supports **bold**, *italic*, and `inline code`.

        - Item one
        - Item two
        - Item three
        """;

    var parser = Parser.builder().build();
    var renderer = HtmlRenderer.builder().build();

    var document = parser.parse(markdown);
    var html = renderer.render(document);

    System.out.println(html);
}

The example converts a Markdown string into an HTML string.

var renderer = HtmlRenderer.builder().build();

An HtmlRenderer is built using its builder. It transforms the AST into an HTML string.

var html = renderer.render(document);

The render method takes the parsed document and produces an HTML string. The result includes standard HTML tags such as <h1>, <p>, <strong>, <em>, <ul>, and <li>.

Shared parser and renderer configuration

Both the parser and renderer can share a single MutableDataSet configuration object. This ensures that extensions and options are applied consistently.

Main.java
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.data.MutableDataSet;

void main() {

    var options = new MutableDataSet();

    var parser = Parser.builder(options).build();
    var renderer = HtmlRenderer.builder(options).build();

    var markdown = """
        ## Configuration

        Both parser and renderer share the same options.
        """;

    var html = renderer.render(parser.parse(markdown));
    System.out.println(html);
}

A MutableDataSet holds all configuration options. Passing the same instance to both builders ensures that extensions registered via the options are available to both the parser and the renderer.

Using extensions

Flexmark provides numerous extensions for GitHub-Flavored Markdown features such as tables, task lists, and strikethrough. The following example demonstrates how to enable them.

Main.java
import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension;
import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension;
import com.vladsch.flexmark.ext.tables.TablesExtension;
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.data.MutableDataSet;

import java.util.List;

void main() {

    var options = new MutableDataSet();
    options.set(Parser.EXTENSIONS, List.of(
            TablesExtension.create(),
            TaskListExtension.create(),
            StrikethroughExtension.create()));

    var parser = Parser.builder(options).build();
    var renderer = HtmlRenderer.builder(options).build();

    var markdown = """
        ## Extensions Demo

        | Name  | Price |
        |-------|-------|
        | Book  | $12   |
        | Pen   | $2    |

        - [x] Learn Flexmark
        - [ ] Write article
        - [ ] Publish

        This is ~~deprecated~~ updated.
        """;

    var html = renderer.render(parser.parse(markdown));
    System.out.println(html);
}

The example enables table, task list, and strikethrough extensions.

options.set(Parser.EXTENSIONS, List.of(
        TablesExtension.create(),
        TaskListExtension.create(),
        StrikethroughExtension.create()));

Extensions are registered via the Parser.EXTENSIONS key. Each extension is created with its static factory method and added to a list. These extensions are then automatically available to both the parser and the renderer.

| Name  | Price |
|-------|-------|
| Book  | $12   |
| Pen   | $2    |

Tables are defined using pipe characters and hyphens. The first row is the header, and the second row defines the column alignment.

- [x] Learn Flexmark
- [ ] Write article

Task lists use the [ ] and [x] syntax for unchecked and checked items respectively.

This is ~~deprecated~~ updated.

Strikethrough text is marked with double tildes ~~.

Customizing rendering options

Flexmark allows customization of HTML output through various options. The following example shows how to configure soft breaks and unsafe HTML rendering.

Main.java
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.data.MutableDataSet;

void main() {

    var options = new MutableDataSet();
    options.set(HtmlRenderer.SOFT_BREAK, "<br />");

    var parser = Parser.builder(options).build();
    var renderer = HtmlRenderer.builder(options).build();

    var markdown = """
        Line one
        Line two

        Line three
        """;

    var html = renderer.render(parser.parse(markdown));
    System.out.println(html);
}

The SOFT_BREAK option controls how line breaks within a paragraph are rendered. By setting it to <br />, single line breaks in the Markdown source become HTML line breaks.

options.set(HtmlRenderer.SOFT_BREAK, "<br />");

The default behaviour translates a soft break into a space. Setting it to <br /> makes single newlines visible in the rendered HTML.

Wrapping HTML with CSS

When embedding rendered Markdown in a Swing application or web page, it is useful to wrap the HTML body with a full document structure including CSS styling.

Main.java
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.data.MutableDataSet;

void main() {

    var options = new MutableDataSet();
    options.set(HtmlRenderer.SOFT_BREAK, "<br />");

    var parser = Parser.builder(options).build();
    var renderer = HtmlRenderer.builder(options).build();

    var markdown = """
        ## Styled Output

        This Markdown is rendered with custom CSS styling.
        """;

    var body = renderer.render(parser.parse(markdown));
    var css = """
        body {
            font-family: "Segoe UI", Roboto, sans-serif;
            font-size: 14px;
            line-height: 1.6;
            padding: 20px;
            color: #333;
            text-align: left;
        }
        h2 { color: #2c3e50; }
        """;

    var fullHtml = """
        <!DOCTYPE html>
        <html>
        <head>
            <meta charset="UTF-8">
            <style>%s</style>
        </head>
        <body>%s</body>
        </html>
        """.formatted(css, body);

    System.out.println(fullHtml);
}

The example renders Markdown to HTML and wraps the result in a complete HTML document with embedded CSS styles. This approach is especially useful when displaying Markdown in JEditorPane or similar Swing components.

var body = renderer.render(parser.parse(markdown));

The Markdown is first parsed and rendered into an HTML body fragment.

var fullHtml = """
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <style>%s</style>
    </head>
    <body>%s</body>
    </html>
    """.formatted(css, body);

The HTML body and CSS are embedded into a full HTML document using a text block template and the formatted method for string interpolation.

Reading Markdown from a file

In practice, Markdown content is often stored in files. The next example reads a Markdown file and renders it to HTML.

src/main/resources/sample.md
# Sample Document

## Introduction

This is a sample Markdown file with **formatted** text.

### Code Example

```java
record Point(int x, int y) {
    Point translate(int dx, int dy) {
        return new Point(x + dx, y + dy);
    }
}
```

We have a sample Markdown file with a heading, formatted text, and a fenced code block.

Main.java
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.data.MutableDataSet;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

void main() throws IOException {

    var filePath = Path.of("src/main/resources/sample.md");
    var markdown = Files.readString(filePath);

    var options = new MutableDataSet();

    var parser = Parser.builder(options).build();
    var renderer = HtmlRenderer.builder(options).build();

    var html = renderer.render(parser.parse(markdown));

    var outputPath = Path.of("sample.html");
    Files.writeString(outputPath, html);

    System.out.println("HTML written to " + outputPath.toAbsolutePath());
}

The example reads Markdown from a file, renders it to HTML, and writes the output to another file.

var filePath = Path.of("src/main/resources/sample.md");
var markdown = Files.readString(filePath);

The Files.readString method reads the entire Markdown file into a string. It uses UTF-8 encoding by default.

var outputPath = Path.of("sample.html");
Files.writeString(outputPath, html);

The rendered HTML is written to a file using Files.writeString.

In this article we have worked with the Flexmark library, which implements the CommonMark specification. We have parsed Markdown strings, rendered them to HTML, enabled extensions for GitHub-Flavored Markdown, customized rendering options, and wrapped HTML output with CSS styling.

Source

Flexmark Java documentation

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Java tutorials.