Dear ImGui Bundle includes libraries for syntax-highlighted text editing and markdown rendering.
rich_md - Markdown Rendering¶
Introduction¶
imgui_rich_md renders markdown content directly in your ImGui interface: headers, emphasis, links, lists, tables, images, code blocks with syntax highlighting, LaTeX math, admonitions and collapsible sections. Its text can be selected with the mouse and copied (Ctrl+C, Cmd+C on macOS); a right click also copies it as markdown. It is a standalone library that also works on stock Dear ImGui (C++); Dear ImGui Bundle includes it, with Python bindings.
In Python the module is imgui_bundle.rich_md; in C++ the namespace is RichMd. The former names, imgui_md (Python) and ImGuiMd (C++), remain available as aliases.
Quick example:
from imgui_bundle import rich_md, immapp
def gui():
rich_md.render("""
# Hello Markdown
This is **bold** and this is *italic*.
- List item 1
- List item 2
""")
immapp.run(gui, with_markdown=True)rich_md.render(s) removes the common indentation of the string first, so that a string written inside an indented function renders as expected. rich_md.render_raw(s) renders it as is.
#include "immapp/immapp.h"
#include "imgui_rich_md/rich_md.h"
void gui() {
RichMd::Render(R"(
# Hello Markdown
This is **bold** and this is *italic*.
- List item 1
- List item 2
)");
}
int main() {
ImmApp::RunWithMarkdown(gui);
return 0;
}Images¶
rich_md supports images from local assets and from URLs.
Standard markdown images:

HTML img tags with explicit size:
<img src="https://example.com/photo.jpg" width="200">
<img src="images/logo.png" width="100" height="50">LaTeX math¶
rich_md renders inline and display LaTeX math with MicroTeX (the bundle uses a fork).
Quick example:
from imgui_bundle import rich_md, immapp
def gui():
rich_md.render(r"""
# Math in markdown
Inline math sits on the text baseline: $E = mc^2$, $\sqrt{a^2 + b^2}$,
$\sum_{i=0}^{n} i = \frac{n(n+1)}{2}$.
Display math is centered on its own line:
$$
x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
$$
Sums, integrals, matrices all work:
$$
\int_{-\infty}^{\infty} e^{-x^2}\, dx = \sqrt{\pi}
\qquad
A = \begin{pmatrix} a & b \\ c & d \end{pmatrix}
\qquad
e^{i\pi} + 1 = 0
$$
""")
immapp.run(gui, with_latex=True) # implies with_markdown=TrueNote the raw string (r"""..."""): without it, Python would interpret sequences like \theta as escape characters and silently corrupt the LaTeX.
#include "immapp/immapp.h"
#include "imgui_rich_md/rich_md.h"
void gui() {
RichMd::Render(R"(
# Math in markdown
Inline math: $E = mc^2$, $\sqrt{a^2 + b^2}$.
$$
x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
$$
)");
}
int main() {
ImmApp::AddOnsParams addons;
addons.withLatex = true; // implies withMarkdown=true
HelloImGui::SimpleRunnerParams simple;
simple.guiFunction = gui;
ImmApp::Run(simple, addons);
return 0;
}Mermaid diagrams¶
```mermaid blocks are drawn natively, with ImDrawList and the colors of the ImGui style: flowcharts, sequence diagrams and class diagrams (a subset of Mermaid). A diagram that cannot be parsed is shown as code, with the line of the error.
```mermaid
flowchart LR
A[Markdown] --> B{Mermaid block?}
B -->|yes| C([Parse]) --> D[Layout]
B -->|no| E[Code block]
```To draw a diagram outside of markdown: rich_md.render_mermaid(source) (Python), RichMd::RenderMermaid(source) (C++). The library’s Mermaid tour shows more of them, and what is supported lists the syntax it reads and how its layout differs from mermaid.js.
Documents¶
A long text reads better as a document: a scroll area of its own, a table of contents beside it, links between its sections, and a search.
from imgui_bundle import imgui, immapp, rich_md
def gui() -> None:
with rich_md.document("doc"):
rich_md.render("# Intro\n\nSee [the widgets](#a-section-of-widgets).\n\n## Details\n\nSome text.")
rich_md.document_heading(2, "A section of widgets")
imgui.button("A button")
rich_md.render("## The end\n\nBack to [the top](#intro).")
immapp.run(gui, with_markdown=True)#include "immapp/immapp.h"
#include "imgui_rich_md/rich_md.h"
void Gui()
{
RichMd::BeginDocument("doc");
RichMd::Render("# Intro\n\nSee [the widgets](#a-section-of-widgets).\n\n## Details\n\nSome text.");
RichMd::DocumentHeading(2, "A section of widgets");
ImGui::Button("A button");
RichMd::Render("## The end\n\nBack to [the top](#intro).");
RichMd::EndDocument();
}
int main() {
ImmApp::AddOnsParams addons;
addons.withMarkdown = true;
HelloImGui::SimpleRunnerParams simple;
simple.guiFunction = Gui;
ImmApp::Run(simple, addons);
return 0;
}Between the start and the end of a document, call
render()as many times as you like, and any other widget: they share one table of contents and one search.document_heading()gives a section made of widgets its heading.A link
[text](#slug)reaches a heading of any render of the document. The slugs are made as GitHub does:## Headings and anchorsis#headings-and-anchors, and a repeated title gets-1,-2.The search opens with Ctrl+F (Cmd+F on macOS), or with the magnifier of a narrow document. Enter goes to the next match, Shift+Enter to the previous one. The matches are also listed under the find bar and in the Search tab, and marked on the scrollbar.
The search also finds the text of the collapsed sections (a jump opens them), of the code blocks, and of the formulas (their LaTeX source).
Headings that fold: with
foldable_headingsinDocumentOptions(or in the context’sMarkdownOptions), an arrow at the left of each heading, from##on, folds its section until the next heading of the same level or above, across the renders.document_heading()returns False when its section is folded: skip its widgets then. The right-click menu and the “...” menu of the table of contents fold or unfold them all, asfold_all_headings()does.render_document(id, markdown)is the one-call form, andDocumentOptionssets the table of contents, the search, the scroll’s animation and the folds.
Demo: Try online | Python | C++
Narrative programming¶
A program can tell its own story. Its comments and strings hold named markdown sections (::md Name) and code regions (::code), and markdown transcludes them with an embed alone on its line, as in Obsidian: ![[#Square]] for the prose of a section, ![[#Square#code]] for its code, ![[other_file.py#Name]] for another file. The story chooses its order; the program keeps its own.
from imgui_bundle import immapp, rich_md
r"""::md Intro
# A program that tells its own story
The story picks the parts of the file it needs, in its own order:
![[#Square]]
![[#Square#code]]
"""
# ::md Square
# The square of a number, $x^2$:
# ::code
def square(x: float) -> float:
return x * x
# ::endcode
def gui() -> None:
rich_md.render_this_file("Intro")
immapp.run(gui, with_latex=True)#include "immapp/immapp.h"
#include "imgui_rich_md/rich_md.h"
/*::md Intro
# A program that tells its own story
The story picks the parts of the file it needs, in its own order:
![[#Square]]
![[#Square#code]]
*/
// ::md Square
// The square of a number, $x^2$:
// ::code
float Square(float x) { return x * x; }
// ::endcode
void Gui() { RICHMD_RENDER_THIS_FILE("Intro"); }
int main() {
ImmApp::AddOnsParams addons;
addons.withLatex = true;
HelloImGui::SimpleRunnerParams simple;
simple.guiFunction = Gui;
ImmApp::Run(simple, addons);
return 0;
}RICHMD_RENDER_THIS_FILE reads the source file (__FILE__) at run time: the source must be present where the program runs.
render_this_file("Intro") renders the section Intro of the calling file, its transclusions resolved. A section written in line comments ends with its code (::endcode), or with ::endmd when it has none; a section in a string or a block comment ends with it.
Example: the Mandelbrot set as a map of Julia sets, an interactive lesson in a single Python file (source). The idea: narrative programming; the syntax in full: specification.
Full Demo¶
Try online | Python | C++
The library’s own examples, on stock Dear ImGui (C++): a tour of every feature, an editor, a custom host, fonts. Try online | C++
Documented APIs¶
Python: rich_md.pyi
C++: rich_md.h (and rich_md_host.h to plug your own textures, assets or downloads)
ImGuiColorTextEdit - Syntax Highlighting Editor & Diff Viewer¶
Introduction¶
ImGuiColorTextEdit is a syntax highlighting text editor and diff viewer for ImGui (originally by BalazsJako, rewritten from scratch by Johan A. Goossens).
Dear ImGui Bundle uses a fork with a few additions for Python bindings.
Features:
Syntax highlighting for C, C++, Python, GLSL, HLSL, Lua, SQL, AngelScript, C#, JSON, Markdown
Multiple color palettes (dark, light)
Find/replace UI with keyboard shortcuts
Text markers (colored line highlights with tooltips)
Bracket matching with visual indicators
Line decorators (custom gutter content per line, e.g. breakpoints)
Context menu callbacks (separate for line numbers and text area)
Change and transaction callbacks
Filter selections/lines (transform text via callbacks)
Autocomplete framework
Undo/redo, copy/paste, multi-cursor support
TextDiff widget: combined and side-by-side diff view for comparing two texts
Full Demo¶
Try online | Python | C++
Documented APIs¶
Python: imgui
_color _text _edit .pyi C++: TextEditor.h | TextDiff.h