Building a Markdown Editor Extension for Mendix Studio Pro
Mendix 11 introduced an exciting capability: building custom document editors directly in Studio Pro. In this tutorial, we'll build a Markdown editor extension from scratch using TypeScript and React.
Why Build Custom Document Editors?
With .NET extensions no longer actively developed, the new TypeScript/React-based extension system offers a modern approach to extending Studio Pro. Custom document editors allow you to:
- Edit specialized file formats directly in Studio Pro
- Integrate third-party libraries and tools
- Create seamless workflows without leaving the IDE
Project Setup
Start by creating a new extension project using the npm scaffolding tool:
npm create mendix-extension
This sets up the basic structure with TypeScript and React support. For our Markdown editor, we'll use the MDX Editor - an open-source React library specifically designed for Markdown editing.
Project Structure
Your extension will have the following key files:
my-extension/
├── main/
│ └── index.ts # Main entry point
├── editor/
│ └── editor.tsx # React editor component
├── concepts/
│ └── markdown-type.ts # Document type definition
└── manifest.json # Extension configuration
Step 1: Register the Document Type
In main/index.ts, register your custom document type with the Studio Pro API:
import { registerMarkdownType } from './concepts/markdown-type';
// Register the custom Markdown document type
registerMarkdownType();
This blocks the default document type and registers your Markdown variant.
Step 2: Define Document Type Properties
Create concepts/markdown-type.ts to define the document type:
export function registerMarkdownType() {
// Define icons as Base64 strings (keep them small for fast loading)
const smallIcon = "data:image/png;base64,...";
const largeIcon = "data:image/png;base64,...";
// Define the storage pattern
const storagePattern = {
type: 'blob',
contentType: 'text/markdown'
};
// Register the editor
mx.editor.register({
name: 'Markdown',
icon: smallIcon,
largeIcon: largeIcon,
storagePattern: storagePattern,
defaultContent: '', // Empty by default
editorType: 'fullscreen' // Opens as a full-screen tab, not a popup
});
}
Step 3: Build the React Editor
Create editor/editor.tsx with the MDX Editor component:
import React, { useState, useEffect } from 'react';
import { MDXEditor } from '@mdxeditor/editor';
import '@mdxeditor/editor/style.css';
export function MarkdownEditorComponent() {
const [content, setContent] = useState('');
const [documentId, setDocumentId] = useState(null);
// Load document data from Mendix
useEffect(() => {
async function loadDocument() {
const doc = await mx.document.getById(documentId);
const blobContent = await doc.getContent();
setContent(blobContent);
}
if (documentId) {
loadDocument();
}
}, [documentId]);
// Save changes back to Mendix
const handleChange = (newContent: string) => {
setContent(newContent);
// Update the blob document so it can be manually saved
if (documentId) {
mx.document.updateContent(documentId, newContent);
}
};
return (
<React.StrictMode>
<MDXEditor
markdown={content}
onChange={handleChange}
/>
</React.StrictMode>
);
}
Key Implementation Details
- Data Loading: Use
mx.document.getById()to retrieve the document content from Mendix's blob storage - Data Saving: Update the blob document with
updateContent()when the editor changes - React Strict Mode: Wrap your component for better development experience
Step 4: Configure the Manifest
In manifest.json, define your entry points:
{
"name": "Markdown Editor",
"version": "1.0.0",
"entryPoints": {
"main": "dist/main/index.js",
"editor": "dist/editor/editor.js"
}
}
Step 5: Handle CSS Styling
Add CSS bundling plugins to your build configuration:
// vite.config.js or webpack.config.js
import { copyCSSPlugin } from 'vite-plugin-copy-css';
import { bundleCSSPlugin } from 'vite-plugin-bundle-css';
export default {
plugins: [
copyCSSPlugin(),
bundleCSSPlugin()
]
}
This configuration:
- Combines all CSS files in your project into a single
style.css - Automatically injects it into the final build
Step 6: Build and Deploy
Build your extension:
npm run build
This compiles TypeScript, bundles React components, and combines all CSS files.
Step 7: Load in Studio Pro
- Copy your built extension to the Mendix project's
userlib/extensions/folder - In Studio Pro, go to App > Synchronize App Directory
- Your extension will now be available
Using Your Extension
- In Studio Pro, right-click in the Project Explorer
- Select Add Document
- Choose Markdown from the document types
- Name it (e.g., "Project Plan")
- The Markdown editor opens in a full-screen tab
- Edit your content and save with Ctrl+S
What's Next?
Now that you've built a functional document editor extension, you're ready to explore more advanced topics. In the next post, we'll dive into styling your extension to match Studio Pro's design language and create a polished user experience.