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

Symfony Djot Laravel Package

php-collective/symfony-djot

Symfony integration for Djot, the lightweight markup language. Provides bundle configuration, service wiring, and Twig rendering so you can parse and display Djot content in Symfony applications with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with composer require php-collective/symfony-djot:^0.2. Note this is a Symfony bundle wrapping the Djot parser; in a Laravel app you won't get Twig filters or bundle auto-registration, so plan to bind the converter in a service provider yourself (or use the underlying php-collective/djot-php parser directly and treat this package as the config/extension layer).
  • Look first at the bundle's default config: the safe_mode flag, the enabled-extensions list, and the converter options (significant_newlines, soft_break_mode, xhtml). That config is the whole API surface you'll touch day-to-day.
  • First use case: render user-submitted Djot (comments, forum posts, support tickets) to HTML. With 0.2.0 you get XSS protection for free — safe_mode now defaults to true, so a plain convert() call is safe to output with {!! !!} without extra sanitising.
// app/Providers/DjotServiceProvider.php
$this->app->singleton('djot', fn () => new Converter(safeMode: true));   // user content
$this->app->singleton('djot.raw', fn () => new Converter(safeMode: false)); // trusted content

Implementation Patterns

Two converters, two Blade directives. Mirror the package's |djot / |djot_raw split with Blade directives so intent is visible at the call site:

Blade::directive('djot', fn ($expr) => "<?php echo app('djot')->convert($expr); ?>");
Blade::directive('djotRaw', fn ($expr) => "<?php echo app('djot.raw')->convert($expr); ?>");

Then @djot($comment->body) for user content and @djotRaw($page->body) for CMS/admin-authored content only.

Render at write time, not read time. Djot→HTML is fast but not free on an index of 50 posts. Store both body_djot and body_html on save (or cache keyed by md5($body)), and re-render on update. This also keeps safe-mode decisions frozen per record instead of per request.

Pick extensions per surface, not globally. The six new extensions are content-type specific:

  • admonition, tabs, code_group — documentation and knowledge-base pages.
  • inline_footnotes, heading_reference — long-form articles; heading_reference gives you auto-anchors you can harvest for a table of contents.
  • heading_level_shift — essential when embedding a Djot fragment into a page that already has an <h1>; set the shift on the embedded-content converter only.

Use the new converter options deliberately. soft_break_mode is the one you want for chat-style/comment rendering where a single newline should become <br>. significant_newlines matters if you're round-tripping prose where blank lines are meaningful. xhtml is for HTML email (Laravel mailables) and export pipelines — turn it on only in the mailable renderer, not globally.

Integration points. API resources returning { djot, html } pairs; mailables that convert Djot to HTML then @include it into a Blade mail template with xhtml: true; an import command that converts legacy Markdown bodies through Djot once, offline.

Gotchas and Tips

  • The 0.2.0 breaking change is the whole review. safe_mode flipping to true means any existing pipeline that relied on raw HTML passthrough will now see it escaped or stripped. Grep your codebase and DB for Djot content containing raw HTML (<div, <iframe, <script) and decide per source. Anything from a CMS editor gets |djot_raw; anything from $request never does.
  • Double-escaping trap. safe_mode: true output is already escaped, so output it with {!! !!} — using {{ }} will show literal &lt;p&gt;. Conversely, djot_raw output must also use {!! !!} but is only acceptable on trusted sources. There is no configuration that makes djot_raw safe for user input; the filter name is a warning, not a suggestion.
  • Extension config changes alter existing output. Enabling heading_level_shift or heading_reference retroactively changes heading tags and anchor IDs on already-stored content. If you store rendered HTML, you need a backfill/re-render job, and your TOC links may break. Add a renderer_version column or config hash if you plan to toggle extensions.
  • Snapshot tests will fail on xhtml. Void/self-closing tag differences (<br> vs <br />) break string-equality assertions. Pin the option in test setup rather than inheriting it from config.
  • Symfony bundle wiring doesn't come for free. No Laravel package discovery for Symfony bundles — if you skip the service provider above you'll get "class not found" or an unstubbed converter. Confirm the concrete converter class name from the package's DI config rather than assuming.
  • Pre-1.0 semver. 0.x releases are allowed to break. Pin ^0.2 and read the release notes on every bump — this one already changed a default that silently weakens or breaks output.
  • Debugging. Use php artisan tinker with app('djot')->convert($sample) to isolate parser behaviour from your Blade/view layer. For anything odd, dump the AST (the underlying parser exposes it) instead of guessing from HTML.
  • Config cache. If you later move config into config/djot.php, remember php artisan config:cache in deploy — the classic "works locally, ignored in production" failure.
  • Extension points. Custom renderers/handlers and per-converter config are the supported hooks; register a named converter per surface (docs, comments, email) rather than one global instance with conditional logic inside your controllers.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin