- Introduction
- Mermaid JS
- How to use Mermaid JS in Notion
- Use Whimsical
- Use Miro
- Use Diagrams.net
- Use MindMeister
- Use My Mind Node
- XMind
- Export and Embed
- Directly copy-paste content
- Upcoming : Dockam for Notion
Introduction
I use Notion for everything. It is a solid, all-in-one solution that is constantly being developed and improved. From taking notes to writing blog posts to creating a knowledge base for my team, Notion is my go-to tool.
For brainstorming and knowledge management, there is one thing that Notion doesn't do, and that is mind mapping. Mind mapping is an essential tool that can be used to show both the higher-level bird’s eye view and the low-level relations and links 🖇️ in between the information being presented.
Fortunately, there are various workarounds for this.
Mermaid JS
flowchart LR
PARA ---> Projects
PARA ---> Areas
PARA ---> Resources
PARA ---> Archive
Mermaid JS is a popular javascript library (hence the JS in the name) that can generate infographic content on the go. It is also compatible with other note-taking tools like obsidian. You can start by writing simple text in a specific format (i.e., code) that is then converted to diagrams by Mermaid JS. Its clean syntax makes it easier to generate simple diagrams without having programming as a prerequisite, and the core functionality can be extended further to make complex diagrams.
You can read more about how it works and all the specific features in the official documentation. There is also a live editor which comes in handy. If you want to know how to customize it further, make sure to check out Red Gregory’s video.
How to use Mermaid JS in Notion

- Use Notion’s slash
/
command and type/mermaid
. Click on the popup. - Alternatively, you can add a new code block using
+
from the left sub-menu. Make sure to set the language asMermaid
. - Write your code in the block, and the diagram should be rendered in real time.
- You can choose to show only code or preview from the drop-down options.
Use Whimsical

Whimsical is an app that comes with mind mapping, wireframing, flowcharts, and document creation ability to structure the information easily. Although Whimsical doesn't have a native integration with Notion, you can create your work (in this case, mind map) in Whimsical, make it public, and then paste the Whimsical's mind map URL into Notion and select create embed.
When it comes to mind mapping functionalities, I think Whimsical has a big advantage over Miro as Whimsical's UI and UX are really intuitive. You can almost brainstorm at the speed of thought with Whimsical.
Similar to Notion’s blocks, Whimsical has something called “items” these include folders, files, images, texts, etc. With the free plan, you can only use 500 of these items. You can overcome this restriction by upgrading to the pro plan by paying $10/mo per user. It also has an organized plan for collaborative teams that costs $20/mo per user.
Use Miro

Miro is popularly known for their whiteboard functionality. They also have features like flowcharts, templates, and sticky notes, which makes them ideal for collaborative brainstorming sessions.
Similar to Whimsical, it has native integration with Notion, so you can easily embed your Miro work in Notion pages.
It is the most popular solution out there. If you are already using Miro for other purposes and want to use it for mind mapping as well, then go ahead with it.
If you are tight on budget or not really sure if you want to spend on a mind-mapping tool, then go ahead with Miro. Because the free plan includes three editable boards, and you need to upgrade to $8/user/month to get access to the team's plan.
Since the embed is directly pulling the data live from servers, all the changes that you make in the mind map will be updated automatically in Notion.
Use Diagrams.net

It is an extensive tool that can be used to create diagrams of all sorts, including mind maps. It was previously called draw.io. It comes with many prebuilt templates and shapes that you can use in your drawings. It is privacy-friendly; you don’t even need to create an account to get started. Did I tell you it’s also completely free and open source? So you don’t ever have to worry about data. If you prefer to have a native experience. It also has apps for macOS, Windows, and even Linux. The only downside is the UX isn’t as buttery smooth as with other tools.

You can also use the chrome extension to start creating directly right inside of Notion without needing to switch apps or tabs. You can read more about it in the “How to draw in Notion” post, which explains it in detail.
Use MindMeister

Mind Meister is a very popular cloud-based mind-mapping software. You can't easily embed a published MindMeister mind map in Notion. For that, you need to use a service from Apption to embed Mind Meister using their widget. You can find the steps here.
Part of the reason why their integration with Notion wasn’t smooth could be their push towards Meister note, an alternative note-taking app. A new addition to the Meister suite that also includes Meister Task.
But for most people, I recommend investing in either Whimsical or Miro, as they provide more functionality and can be embedded directly into Notion.
Use My Mind Node

MyMindNode is a service that comes with MindNode (iOS and mac only 🍎) that allows users to publish their mind maps directly on the web. The downside is that as of early 2020, the service is [no longer under active development](https://my.mindnode.com/#:~:text=As of early 2020%2C myMindNode is no longer under active development. Existing myMindNode users can continue to use it%2C but new registration is no longer possible.), making the registrations closed for new users. As an existing MindNode user, I can still continue to use it. You can still play around with the live demo that is available on their website. I really hope MindNode takes mind mapping seriously and moves out of the Apple ecosystem, and releases a web-based interface for editing the mind maps.
I really liked their product and how they've managed to pack it with so many features while maintaining a minimalistic design. The interface is really intuitive, and it's been my go-to mind-mapping software for the past few years.
But I hear you, myMindNode is not under active development, so what are the other options?
XMind

Xmind is one of the most popular mind-mapping tools out there. With over 100M+ app installs for Android 📱, Windows 💻, iOS, and macOS 🍎. Its free tier is also very generous, and you get most of the stuff done with little to no friction. The pro version is priced at $60 per year. There are additional discounts for students, teachers, and NGOs as well.
Some of its core features include presentation mode along with a huge library of prebuilt templates and themes. It also has handwritten styles and an extensive sticker collection that helps bring more life to drawings.
Export and Embed
Most of the other mind-mapping software lets you export the content via PDF and Images (if this isn’t an option, you can always take a screenshot 😉). Then, you can directly embed that into the Notion page.
But to make edits to your mind map, you need to go back to the mind mapping tool, make the required edits, then export and again embed to Notion. Apart from the process already being tedious in itself, sometimes images added in the mindmaps are lost. So you need to be a little bit mindful of this.
Directly copy-paste content

Alternatively, you can just copy the mind map nodes and paste them into Notion. It’ll be pasted in Notion as sub-bullets. Later, you can give it structure. I personally use this approach because embedding is meh 😕 unless required!
The downside to this approach is that every app has its own formatting style and isn’t consistent throughout. This leads to messy and unformatted texts. I use a simple script to help me overcome this, and this has been a lifesaver.
It’s generally not at all a good idea to run javascript code found on the web without completely knowing what it does. So, I would recommend the same advice. Hence, proceed with caution.
I originally found this on this script on keyboard maestro forum and it has been a lifesaver for me. It scans the text for any consistent formatting and then uses standard 4-space indents and hyphens at the start of bulleted lists.
👇🏼 How to use this
Run the below JavaScript code as automation on the Mindmap content you copy, and then paste the output. Use - Keyboard Maestro for Macro or Autohotkey for Windows.
/* eslint-disable max-lines-per-function */
(() => {
"use strict";
// Pasting any outline as nested Markdown bullet lists.
// (with an indent unit of four spaces)
ObjC.import("AppKit");
// main :: IO ()
const main = () =>
either(
// Message displayed if clipboard empty.
alert("Outline pasted as Markdown bullets")
)(
// Value returned.
x => x
)(
bindLR(
clipTextLR()
)(
compose(
Right,
mdBulletNestFromForest,
forestFromIndentedLines,
indentLevelsFromLines,
lines
)
)
);
// ------------------ INDENTED TEXT ------------------
// forestFromIndentedLines :: [(Int, String)] ->
// [Tree String]
const forestFromIndentedLines = tuples => {
const go = xs =>
0 < xs.length ? (() => {
// First line and its sub-tree,
const [depth, body] = Array.from(
xs[0]
),
[tree, rest] = Array.from(
span(compose(lt(depth), fst))(
tail(xs)
)
);
// followed by the rest.
return [
Node(body)(go(tree))
].concat(go(rest));
})() : [];
return go(tuples);
};
// indentLevelsFromLines :: [String] -> [(Int, String)]
const indentLevelsFromLines = xs => {
const
pairs = xs.map(
x => bimap(length)(concat)(
span(isSpace)(list(x))
)
),
indentUnit = pairs.reduce(
(a, tpl) => {
const i = tpl[0];
return 0 < i ? (
i < a ? i : a
) : a;
},
Infinity
);
return [Infinity, 0].includes(indentUnit) ? (
pairs
) : pairs.map(first(n => n / indentUnit));
};
// --------- MARKDOWN BULLET NEST FROM TREE ----------
// mdBulletNestFromForest :: [Tree String] -> String
const mdBulletNestFromForest = xs => {
const go = indent => x => {
const
outline = x.nest.map(
go(` ${indent}`)
);
return [`${indent}- ${x.root}`]
.concat(outline)
.join("\\n");
};
return xs.map(go(""))
.join("\\n");
};
// ----------------------- JXA -----------------------
// alert :: String => String -> IO String
const alert = title =>
s => {
const sa = Object.assign(
Application("System Events"), {
includeStandardAdditions: true
});
return (
sa.activate(),
sa.displayDialog(s, {
withTitle: title,
buttons: ["OK"],
defaultButton: "OK"
}),
s
);
};
// clipTextLR :: () -> Either String String
const clipTextLR = () => (
v => Boolean(v) && 0 < v.length ? (
Right(v)
) : Left("No utf8-plain-text found in clipboard.")
)(
ObjC.unwrap($.NSPasteboard.generalPasteboard
.stringForType($.NSPasteboardTypeString))
);
// --------------------- GENERIC ---------------------
// Left :: a -> Either a b
const Left = x => ({
type: "Either",
Left: x
});
// Node :: a -> [Tree a] -> Tree a
const Node = v =>
// Constructor for a Tree node which connects a
// value of some kind to a list of zero or
// more child trees.
xs => ({
type: "Node",
root: v,
nest: xs || []
});
// Right :: b -> Either a b
const Right = x => ({
type: "Either",
Right: x
});
// Tuple (,) :: a -> b -> (a, b)
const Tuple = a =>
b => ({
type: "Tuple",
"0": a,
"1": b,
length: 2
});
// bimap :: (a -> b) -> (c -> d) -> (a, c) -> (b, d)
const bimap = f =>
// Tuple instance of bimap.
// A tuple of the application of f and g to the
// first and second values respectively.
g => tpl => 2 !== tpl.length ? (
// eslint-disable-next-line no-undef
bimapN(f)(g)(tpl)
) : Tuple(f(tpl[0]))(
g(tpl[1])
);
// bindLR (>>=) :: Either a ->
// (a -> Either b) -> Either b
const bindLR = m =>
mf => m.Left ? (
m
) : mf(m.Right);
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
const compose = (...fs) =>
// A function defined by the right-to-left
// composition of all the functions in fs.
fs.reduce(
(f, g) => x => f(g(x)),
x => x
);
// concat :: [[a]] -> [a]
// concat :: [String] -> String
const concat = xs =>
0 < xs.length ? (
(
xs.every(x => "string" === typeof x) ? (
""
) : []
).concat(...xs)
) : xs;
// either :: (a -> c) -> (b -> c) -> Either a b -> c
const either = fl =>
// Application of the function fl to the
// contents of any Left value in e, or
// the application of fr to its Right value.
fr => e => "Left" in e ? (
fl(e.Left)
) : fr(e.Right);
// first :: (a -> b) -> ((a, c) -> (b, c))
const first = f =>
// A simple function lifted to one which applies
// to a tuple, transforming only its first item.
xy => {
const tpl = Tuple(f(xy[0]))(xy[1]);
return Array.isArray(xy) ? (
Array.from(tpl)
) : tpl;
};
// fst :: (a, b) -> a
const fst = tpl =>
// First member of a pair.
tpl[0];
// isSpace :: Char -> Bool
const isSpace = c =>
// True if c is a white space character.
(/\\s/u).test(c);
// length :: [a] -> Int
const length = xs =>
// Returns Infinity over objects without finite
// length. This enables zip and zipWith to choose
// the shorter argument when one is non-finite,
// like cycle, repeat etc
"GeneratorFunction" !== xs.constructor
.constructor.name ? (
xs.length
) : Infinity;
// lines :: String -> [String]
const lines = s =>
// A list of strings derived from a single
// string delimited by newline and or CR.
0 < s.length ? (
s.split(/[\\r\\n]+/u)
) : [];
// list :: StringOrArrayLike b => b -> [a]
const list = xs =>
// xs itself, if it is an Array,
// or an Array derived from xs.
Array.isArray(xs) ? (
xs
) : Array.from(xs || []);
// lt (<) :: Ord a => a -> a -> Bool
const lt = a =>
b => a < b;
// span :: (a -> Bool) -> [a] -> ([a], [a])
const span = p =>
// Longest prefix of xs consisting of elements which
// all satisfy p, tupled with the remainder of xs.
xs => {
const i = xs.findIndex(x => !p(x));
return -1 !== i ? (
Tuple(xs.slice(0, i))(
xs.slice(i)
)
) : Tuple(xs)([]);
};
// tail :: [a] -> [a]
const tail = xs =>
// A new list consisting of all
// items of xs except the first.
"GeneratorFunction" !== xs.constructor
.constructor.name ? (
(ys => 0 < ys.length ? ys.slice(1) : [])(
list(xs)
)
) : (take(1)(xs), xs);
// take :: Int -> [a] -> [a]
// take :: Int -> String -> String
const take = n =>
// The first n elements of a list,
// string of characters, or stream.
xs => "GeneratorFunction" !== xs
.constructor.constructor.name ? (
xs.slice(0, n)
) : [].concat(...Array.from({
length: n
}, () => {
const x = xs.next();
return x.done ? [] : [x.value];
}));
// MAIN ---
return main();
})();
Upcoming : Dockam for Notion
This upcoming tool is a true thread killer for mindmaps in Notion. It has the ability to create 2 way sync flow charts with from toggles, bullets and even checklists. It has support for Images as well. The most exciting feature of this tools is that it can even generate mindmaps from databases. I am eagerly waiting for the launch. I’ve had the pleasure to chat with Jules Libert, creator of the tool. He’s currently finding time in between freelancing and other side projects to work on it.

Happy mind mapping :-)