English | 中文 | Español | Français | Português | Русский | 日本語 | 한국어
Mind elixir is a open source JavaScript mind map core. You can use it with any frontend framework you like.
- Fluent UX - Smooth and intuitive interactions
 - Well designed - Clean and modern interface
 - Mobile friendly - Touch events for mobile devices
 - Efficient shortcuts - Keyboard shortcuts for power users
 
- Lightweight - Minimal bundle size
 - High performance - Optimized for large mind maps
 - Framework agnostic - Works with any frontend framework
 - Pluginable - Extensible architecture
 
- Interactive editing - Built-in drag and drop / node edit capabilities
 - Bulk operations - Multi-node selection and operations
 - Undo / Redo - Complete operation history
 - Node connections & summarization - Custom node linking and content summarization
 
- Multiple export formats - SVG / PNG / HTML export
 - Easy styling - Customize mindmap with CSS variables
 - Theme support - Built-in themes and custom styling
 
Table of Contents
- Vanilla JS - https://codepen.io/ssshooter/pen/vEOqWjE
 - React - https://codesandbox.io/p/devbox/mind-elixir-3-x-react-18-x-forked-f3mtcd
 - Vue3 - https://codesandbox.io/p/sandbox/mind-elixir-3-x-vue3-lth484
 
npm i mind-elixir -Simport MindElixir from 'mind-elixir'; import "mind-elixir/style.css";<script type="module" src="https://cdn.jsdelivr.net/npm/mind-elixir/dist/MindElixir.js"></script>And in your CSS file:
@import "https://cdn.jsdelivr.net/npm/mind-elixir/dist/style.css";<div id="map"></div> <style> #map { height: 500px; width: 100%; } </style>import MindElixir from 'mind-elixir' import "mind-elixir/style.css"; import example from 'mind-elixir/dist/example1' let options = { el: '#map', // or HTMLDivElement direction: MindElixir.LEFT, draggable: true, // default true contextMenu: true, // default true toolBar: true, // default true nodeMenu: true, // default true keypress: true, // default true locale: 'en', // [zh_CN,zh_TW,en,ja,pt,ru] waiting for PRs overflowHidden: false, // default false mainLinkStyle: 2, // [1,2] default 1 mouseSelectionButton: 0, // 0 for left button, 2 for right button, default 0 contextMenuOption: { focus: true, link: true, extend: [ { name: 'Node edit', onclick: () => { alert('extend menu') }, }, ], }, before: { insertSibling(type, obj) { return true }, }, } let mind = new MindElixir(options) mind.install(plugin) // install your plugin // create new map data const data = MindElixir.new('new topic') // or `example` // or the data return from `.getData()` mind.init(data) // get a node MindElixir.E('node-id')// whole node data structure up to now const nodeData = { topic: 'node topic', id: 'bd1c24420cd2c2f5', style: { fontSize: '32', color: '#3298db', background: '#ecf0f1' }, expanded: true, parent: null, tags: ['Tag'], icons: ['😀'], hyperLink: 'https://github.com/ssshooter/mind-elixir-core', image: { url: 'https://raw.githubusercontent.com/ssshooter/mind-elixir-core/master/images/logo2.png', // required // you need to query the height and width of the image and calculate the appropriate value to display the image height: 90, // required width: 90, // required }, children: [ { topic: 'child', id: 'xxxx', // ... }, ], }mind.bus.addListener('operation', operation => { console.log(operation) // return { // name: action name, // obj: target object // } // name: [insertSibling|addChild|removeNode|beginEdit|finishEdit] // obj: target // name: moveNode // obj: {from:target1,to:target2} }) mind.bus.addListener('selectNodes', nodes => { console.log(nodes) }) mind.bus.addListener('expandNode', node => { console.log('expandNode: ', node) })// data export const data = mind.getData() // javascript object, see src/example.js mind.getDataString() // stringify object mind.getDataMd() // markdown // data import // initiate let mind = new MindElixir(options) mind.init(data) // data update mind.refresh(data)let mind = new MindElixir({ // ... before: { async addChild(el, obj) { await saveDataToDb() return true }, }, })Install @ssshooter/modern-screenshot, then:
import { domToPng } from '@ssshooter/modern-screenshot' const download = async () => { const dataUrl = await domToPng(mind.nodes, { padding: 300, quality: 1, }) const link = document.createElement('a') link.download = 'screenshot.png' link.href = dataUrl link.click() }const options = { // ... theme: { name: 'Dark', // main lines color palette palette: ['#848FA0', '#748BE9', '#D2F9FE', '#4145A5', '#789AFA', '#706CF4', '#EF987F', '#775DD5', '#FCEECF', '#DA7FBC'], // overwrite css variables cssVar: { '--main-color': '#ffffff', '--main-bgcolor': '#4c4f69', '--color': '#cccccc', '--bgcolor': '#252526', '--panel-color': '255, 255, 255', '--panel-bgcolor': '45, 55, 72', }, // all variables see /src/index.less }, // ... } // ... mind.changeTheme({ name: 'Latte', palette: ['#dd7878', '#ea76cb', '#8839ef', '#e64553', '#fe640b', '#df8e1d', '#40a02b', '#209fb5', '#1e66f5', '#7287fd'], cssVar: { '--main-color': '#444446', '--main-bgcolor': '#ffffff', '--color': '#777777', '--bgcolor': '#f6f6f6', }, })Be aware that Mind Elixir will not observe the change of prefers-color-scheme. Please change the theme manually when the scheme changes.
| Shortcut | Function | 
|---|---|
| Enter | Insert Sibling Node | 
| Tab | Insert Child Node | 
| F1 | Center the Map | 
| F2 | Begin Editing the Current Node | 
| ↑ | Select the Previous Sibling Node | 
| ↓ | Select the Next Sibling Node | 
| ← / → | Select Parent or First Child | 
| PageUp / Alt + ↑ | Move Up Node | 
| PageDown / Alt + ↓ | Move Down Node | 
| Ctrl + ↑ | Change Layout Pattern to Side | 
| Ctrl + ← | Change Layout Pattern to Left | 
| Ctrl + → | Change Layout Pattern to Right | 
| Ctrl + C | Copy the Current Node | 
| Ctrl + V | Paste the Copied Node | 
| Ctrl + "+" | Zoom In Mind Map | 
| Ctrl + "-" | Zoom Out Mind Map | 
| Ctrl + 0 | Reset Zoom Level | 
- @mind-elixir/node-menu
 - @mind-elixir/node-menu-neo
 - @mind-elixir/export-xmind
 - @mind-elixir/export-html
 - mind-elixir-react
 
PRs are welcome!
pnpm i pnpm dev Test generated files with dev.dist.ts:
pnpm build pnpm link ./ Update docs:
# Install api-extractor pnpm install -g @microsoft/api-extractor # Maintain /src/docs.ts # Generate docs pnpm doc pnpm doc:md Use DeepWiki to learn more about Mind Elixir
Thanks for your contributions to Mind Elixir! Your support and dedication make this project better.
- Move scroll-based movement to transition-based movement
 Summary.text->Summary.label- Remove 
getDataMd() - MindElixir.dragMoveHelper -> instance.dragMoveHelper
 - Remove 
unselectNode() - Remove 
selectNodeevent, useselectNodesevent instead - Remove 
removeNode() node.style.fontSize: use string instead of number which means you should addpxto the end- Use 
instance.findElinstead ofMindElixir.Eto get a node element - CSS file is separated from JS file, you need to import it manually 
- If using a bundler with CSS support: 
import "mind-elixir/style.css"; - If using a CDN you can add to your CSS file: 
@import "https://cdn.jsdelivr.net/npm/mind-elixir@^5.0.0/dist/style.css"; 
 - If using a bundler with CSS support: 
 
 