Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Simplemde Bundle Laravel Package

ns/simplemde-bundle

ns/simplemde-bundle integrates the SimpleMDE markdown editor into Laravel applications, providing a lightweight, embeddable editor with live preview, toolbar controls, and plain markdown output. It supplies the assets and framework wiring needed to add markdown editing to forms quickly.

View on GitHub
Deep Wiki
Context7

Getting Started

The first thing to internalize is that ns/simplemde-bundle is a Symfony bundle, not a Laravel package. Running composer require ns/simplemde-bundle in a Laravel app will pull the code into vendor/, but the bundle's Extension and form types will never be registered — Laravel's service container doesn't know about Symfony's bundle bootstrapping. Treat the repo as reference material, not as a dependency.

What you actually want is the editor it wraps. Two paths:

  1. Extract the concept. Read Form/Type/SimpleMDEType.php and the accompanying Twig template in the repo. Together they show you the contract: a textarea + a data-* attribute carrying editor config + a JS initializer. That's ~40 lines you can port to a Blade component in an afternoon.
  2. Install the underlying JS library directly. npm install easymde (see Gotchas — the original simplemde package is unmaintained). Then wire it in resources/js/app.js or a dedicated module.

First use case to target: a resources/views/components/markdown-editor.blade.php component that renders a <textarea {{ $attributes }}> and lazily boots EasyMDE against it. Drop it into any form — blog posts, ticket bodies, changelog entries — and you're done.

{{-- resources/views/components/markdown-editor.blade.php --}}
<textarea {{ $attributes->merge(['data-markdown-editor' => true]) }}>{{ $slot }}</textarea>

@push('scripts')
<script type="module">
  import EasyMDE from 'easymde';
  document.querySelectorAll('[data-markdown-editor]').forEach(el => {
    new EasyMDE({ element: el, spellChecker: false });
  });
</script>
@endpush

Implementation Patterns

Blade component + @push('scripts'). The Symfony bundle relies on Twig's {% block javascripts %} inheritance; the Laravel equivalent is @push/@stack. Keep the initialization script inside @once to avoid duplicate instantiation when the component is reused.

Livewire / Alpine integration. EasyMDE manipulates the DOM outside Livewire's scope, so wire:model won't pick up keystrokes. Bridge it:

new EasyMDE({ element: el }).codemirror.on('change', () => {
  el.dispatchEvent(new Event('input', { bubbles: true }));
});

For Livewire 3, $wire.$set('body', editor.value()) on the change event is cleaner than faking the input event. Either way, also listen for livewire:navigated to re-instantiate — the editor dies after SPA-style navigation.

Vite vs Mix. The bundle historically ships compiled assets to public/. Modern Laravel: import EasyMDE in resources/js/app.js and let Vite handle bundling and CSS (import 'easymde/dist/easymde.min.css';). Don't hand-copy assets into public/ — you lose HMR and cache-busting.

Validation & rendering pipeline. The form side is trivial; the interesting work is downstream. Persist the raw markdown string (a longText column is fine). On render, run it through league/commonmark:

$html = (new CommonMarkConverter([
    'html_input' => 'strip',
    'allow_unsafe_links' => false,
]))->convert($post->body);

html_input => 'strip' is the important knob — it neutralizes raw HTML pasted by users. If you need to allow HTML (trusted admins), switch to 'escape' and run the result through mews/purifier or a strict allow-list.

Multiple editors on one page. The Symfony bundle handles this via unique field IDs. In Blade, give each textarea a distinct id and scope your init loop by data-markdown-editor — the snippet above already does this.

Config parity. The bundle exposes toolbar/status/preview options through Symfony form options. Mirror that with a PHP array prop passed to the component:

<x-markdown-editor name="body" :config="['toolbar' => ['bold','italic','link','preview'], 'minHeight' => '200px']" />

Serialize to a data-config attribute and JSON.parse it in the initializer.

Gotchas and Tips

  • The Symfony bundle is not drop-in for Laravel. This is the single biggest pitfall. No config/app.php provider registration, no php artisan vendor:publish. If a tutorial says otherwise, it's for Symfony Flex.
  • simplemde itself is deprecated. The upstream project was abandoned around 2018/2019; the maintained fork is EasyMDE. The bundle wraps the original, so if you port its patterns, port them to EasyMDE's API — most options are identical, but spell-check, toolbar customization, and the codemirror instance handle all improved.
  • Editor destroyed on Livewire re-render. Any $refresh or redirect unmounts the textarea. Hook livewire:navigated and livewire:load (or Livewire 3's init hook) to rebuild the editor. Use a data-initialized flag to prevent double-init, which produces a "CodeMirror already attached" error.
  • The textarea must be visible on init. If you render the editor inside a hidden tab/modal, EasyMDE measures zero height and looks broken. Initialize lazily — on shown.bs.tab, x-show trigger, or a small MutationObserver.
  • CSS side effects. EasyMDE injects its own styles into the shadow of nothing — it expects easymde.min.css loaded globally. If you import it inside a scoped module, Tailwind's preflight can reset the toolbar's padding and break icons. Load editor CSS after your app CSS.
  • Toolbar customization is finicky. To drop the default toolbar, pass toolbar: false. To customize, define the array fully — partial arrays fall back to defaults, which is surprising.
  • CSRF and form submission. EasyMDE updates the underlying <textarea> value automatically, so @csrf + normal form POST works without any JS glue. This is the one place the Symfony and Laravel stories are identical.
  • Sanitize on render, not on save. Store the raw markdown; sanitize at display time. If you sanitize on save you're stuck if your policy ever loosens, and you'll corrupt code fences containing HTML examples.
  • codemirror dependency pin. EasyMDE depends on CodeMirror 5 (not 6). If you're also using CodeMirror 6 elsewhere in the app, they'll coexist but bundle size grows — consider lazy-loading EasyMDE with a dynamic import() on the pages that need it.
  • Preview rendering mismatch. EasyMDE's built-in preview uses a Markdown renderer that differs subtly from league/commonmark (tables, autolinks, task lists extension flags). Users will report "it looks different in the preview than in the published post." Align by enabling matching extensions in CommonMark (league/commonmark's TableExtension, AutolinkExtension, TaskListExtension map closely).
  • Extension point worth stealing: the bundle registers a Twig form theme so the textarea carries data-* attributes. In Laravel, do the equivalent via a Blade macro on Form::textarea (if you use laravelcollective/html) or an @aware directive inside your component — keeps call sites terse.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels