runio/mde

A Symfony bundle providing a Markdown editor with WYSIWYG capabilities and first-class RTL/LTR support

Maintainers

Package info

github.com/RunIO-dev/runio-mde

Type:symfony-bundle

pkg:composer/runio/mde

Statistics

Installs: 10

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.2 2026-03-15 17:23 UTC

This package is auto-updated.

Last update: 2026-04-15 17:42:00 UTC


README

Latest Version License PHP Version Symfony Version Tests

A Symfony bundle providing a WYSIWYG Markdown editor with first-class RTL and LTR support for Arabic, Hebrew, Persian, Urdu, and all LTR languages. Built on top of Toast UI Editor with deep Symfony integration.

Why This Bundle?

  • Perfect RTL + LTR Support - Designed for Arabic, Hebrew, Persian, Urdu, and all LTR content
  • WYSIWYG & Markdown - Switch between visual editing and markdown mode seamlessly
  • Security First - Built-in XSS protection and HTML sanitization
  • Highly Customizable - Themes, toolbars, preview modes, and more
  • Production Ready - 119 tests, fully documented
  • Easy Integration - Drop-in Symfony Form Type, ready in minutes
  • Multi-language - Automatic RTL detection, mixed LTR/RTL content support

Requirements

  • PHP: 8.1 or higher
  • Symfony: 6.0 or 7.0+
  • Composer: 2.0 or higher

Installation

Step 1: Install via Composer

composer require runio/mde

Step 2: Enable the Bundle (Symfony Flex does this automatically)

If you're not using Symfony Flex, manually enable the bundle:

// config/bundles.php
return [
    // ...
    Runio\MarkdownEditorBundle\RunioMarkdownEditorBundle::class => ['all' => true],
];

Step 3: Install Assets

php bin/console assets:install --symlink

Step 4: Register Form Theme

# config/packages/twig.yaml
twig:
    form_themes:
        - '@RunioMarkdownEditor/form/markdown_editor_widget.html.twig'

Quick Start

1. Create a Form Type

use Runio\MarkdownEditorBundle\Form\Type\MarkdownEditorType;

class PostType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('title')
            ->add('content', MarkdownEditorType::class, [
                'rtl_enabled' => true,
                'language' => 'ar',
                'editor_height' => '500px',
            ]);
    }
}

2. Render in Template

{{ form_start(form) }}
    {{ form_row(form.title) }}
    {{ form_row(form.content) }}
    <button type="submit">Save</button>
{{ form_end(form) }}

3. Display Rendered Content

{{ post.content|markdown }}

Configuration

# config/packages/runio_markdown_editor.yaml
runio_markdown_editor:
    default_config:
        editor_height: '500px'
        editor_mode: 'wysiwyg'       # wysiwyg, markdown, or both
        rtl_enabled: true
        language: 'ar'
        toolbar: 'full'              # full, basic, minimal
        preview_style: 'vertical'    # vertical or tab
        theme: 'light'               # light or dark
        enable_upload: false
        upload_url: null

    markdown:
        html_input: 'escape'
        allow_unsafe_links: false
        enable_table_extension: true
        enable_strikethrough_extension: true
        enable_tasklist_extension: true
        enable_autolink_extension: true

    rtl:
        languages: ['ar', 'he', 'fa', 'ur']
        auto_detect: true
        arabic_font: 'Noto Naskh Arabic'

    sanitization:
        enabled: true
        allowed_tags: [p, br, strong, em, u, s, blockquote, ul, ol, li, a, img, h1, h2, h3, h4, h5, h6, pre, code, table, thead, tbody, tr, th, td, hr, div, span]
        allowed_attributes: [href, src, alt, title, class, id, dir, lang]

Per-Field Override

$builder->add('content', MarkdownEditorType::class, [
    'editor_height' => '600px',
    'editor_mode' => 'both',
    'theme' => 'dark',
    'toolbar' => 'basic',
    'rtl_enabled' => true,
    'language' => 'ar',
]);

Twig Integration

Filters

{{ post.content|markdown }}
{{ post.summary|markdown_inline }}

Functions

{% set html = markdown_to_html(post.content) %}
{% if detect_rtl(post.content) %}
    <div dir="rtl">{{ html }}</div>
{% endif %}

Security

All HTML output is sanitized by default:

  • Script tag removal
  • Event handler blocking (onclick, onerror, etc.)
  • JavaScript URL blocking
  • Whitelist-based tag and attribute filtering
  • Safe URL validation (http, https, mailto, tel only)

Testing

vendor/bin/phpunit

119 tests covering: Form Type (24), Markdown Parser (23), RTL Detector (16), Sanitization (34), Twig Runtime (22).

Documentation

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for your changes
  4. Ensure all tests pass (vendor/bin/phpunit)
  5. Commit and push
  6. Open a Pull Request

License

MIT License. See LICENSE for details.

Credits

Made for the multilingual developer community by RunIO