PHPackages                             m6web/draftjs-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. m6web/draftjs-bundle

AbandonedArchivedSymfony-bundle

m6web/draftjs-bundle
====================

Render Draft.js state to HTML

v0.1.1(9y ago)72.0k2[1 issues](https://github.com/M6Web/DraftjsBundle/issues)[4 PRs](https://github.com/M6Web/DraftjsBundle/pulls)MITPHPPHP &gt;=5.6

Since Feb 15Pushed 9y ago11 watchersCompare

[ Source](https://github.com/M6Web/DraftjsBundle)[ Packagist](https://packagist.org/packages/m6web/draftjs-bundle)[ RSS](/packages/m6web-draftjs-bundle/feed)WikiDiscussions master Synced 2mo ago

READMEChangelog (2)Dependencies (5)Versions (6)Used By (0)

[ ![build:started](https://camo.githubusercontent.com/850ead0e4a2e4f242624cce1f755089b9c5fb7558ad53497a5d488d32828f707/68747470733a2f2f7472617669732d63692e6f72672f4d365765622f44726166746a7342756e646c652e7376673f6272616e63683d6d6173746572)](# "Latest push build on default branch: started")DraftjsBundle
=============

[](#draftjsbundle)

This Symfony bundle aims to convert [Draft.js](https://github.com/facebook/draft-js) state into an equivalent PHP object model and providing necessary tools for rendering html.

Installation
------------

[](#installation)

This library can be easily installed via composer

```
composer require m6web/draftjs-bundle

```

Then register the bundle:

```
# app/AppKernel.php

public function registerBundles()
{
    $bundles = array(
        new M6Web\Bundle\DraftjsBundle\M6WebDraftjsBundle(),
    );
}
```

YAML configuration reference
----------------------------

[](#yaml-configuration-reference)

The configuration allow you to customize class names of blocks, inline styles and text alignment.

```
m6_web_draftjs:
    class_names:
        blocks: # overriding class name of block
            atomic: 'custom-atomic'
            default: 'custom-paragraph'
            list: 'custom-list'
            heading: 'custom-heading'
        inline: # define inline styles class name
            :
        text_alignment: # define text alignment class name
            left: 'text-left'
            center: 'text-center'
            right: 'text-right'
```

The inline key allow any string to customize class name of inline style text, for example, if you want to define the class name of BOLD style, just define your configuration as below:

```
m6_web_draftjs:
    class_names:
        inline:
            bold: 'u-bold'
```

Objects model
-------------

[](#objects-model)

DraftjsBundle follow the Draft.js object model.

```
ContentState : Represent the document
ContentBlock : Represent a single block
DraftEntity : Represent a Draft.js entity
CharacterMetadata : Represent a character with style and entity

```

Draft.js supports
-----------------

[](#draftjs-supports)

DraftjsBundle supports default Draft.js blocks type, has listed below:

```
- atomic
- unstyled
- paragraph
- unordered-list-item
- ordered-list-item
- header-one
- header-two
- header-three
- header-four
- header-five
- header-six
- blockquote

```

You can extends this list by implementing custom renderer has show in section [Renderers](#renderers)

Exception
---------

[](#exception)

- DraftjsException

ContentStateConverter
---------------------

[](#contentstateconverter)

Convert a Draft.js state into php model object.

```
m6_web_draftjs.content_state_converter

```

HtmlBuilder
-----------

[](#htmlbuilder)

Build html from a ContentState object.

```
m6_web_draftjs.html_builder

```

HtmlRenderer
------------

[](#htmlrenderer)

Object for converting and rendering a Draft.js state into html.

```
m6_web_draftjs.html_renderer

```

Renderers
---------

[](#renderers)

In addition to the global HtmlRenderer, we provide the possibility to extends rendering engine by adding new renderers.

We distinguished 3 types of renderer, depending on what you we want to customize,

- [block](#adding-custom-block-renderer)
- [inline entity](#adding-custom-inline-entity-renderer)
- [block entity](#adding-custom-block-entity-renderer)

There is also another renderer not listed here, the ContentRenderer responsible of rendering the HTML within a block from text and inline style.

The only things you have to do is to create a service then tagged it as expected.

### Adding custom block renderer

[](#adding-custom-block-renderer)

First define your service:

```
# block entity renderers
acme_demo.acme_block_renderer:
    class: Acme\Bundle\DemoBundle\Renderer\Block\AcmeBlockRenderer
    parent: m6_web_draft_js.abstract_block_renderer
    calls:
        - [setBlockClassName, ['block-acme']]
    tags:
        - { name: draftjs.block_renderer, alias: draftjs_acme_block_renderer }
```

In order to be fully support by our rendering engine, you must tag your service with draftjs.block\_renderer and you must extend AbstractBlockRenderer who implement the BlockRendererInterface interface.

Illustration with the AcmeBlockRenderer class:

```
namespace Acme\Bundle\DemoBundle\Renderer\Block;

use M6Web\Bundle\DraftjsBundle\Renderer\Block\AbstractBlockRenderer;
use M6Web\Bundle\DraftjsBundle\Model\ContentBlock;

class AcmeBlockRenderer extends AbstractBlockRenderer
{
    /**
     * @param \ArrayIterator $iterator
     * @param array          $entities
     *
     * @return string
     */
    public function render(\ArrayIterator &$iterator, array $entities)
    {
        // you have acces to the global iterator of ContentBlock
        // so just get current item by use curent()
        $contentBlock = $iterator->current();

        // if your renderer is handling the current ContentBlock
        // you must inform the iterator to move to the next entry for next iteration
        $iterator->next();

        // By extending the AbstractBlockRenderer, you can use the ContentRenderer who allow to render inline html
        $content = $this->contentRenderer->render(
            $contentBlock->getText(),
            $contentBlock->getCharacterList(),
            $entities
        );

        if (!$this->template) {
            return $content;
        }

        // You also have access to the templating engine
        return $this->templating->render($this->template, [
            'classNames' => $this->buildClassNames($contentBlock),
            'content' => $content,
        ]);
    }

    /**
     * @param string $type
     *
     * @return bool
     */
    public function supports($type)
    {
        return 'acme' === $type;
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'acme';
    }
}
```

### Adding custom inline entity renderer

[](#adding-custom-inline-entity-renderer)

Inline renderer are used for displaying entity information in block content has string.

```
function createLink() {
    return DraftEntity.__create('LINK', 'MUTABLE', {uri: 'zombo.com'});
}
```

First define your service:

```
acme_demo.link_inline_entity_renderer:
    class: Acme\Bundle\DemoBundle\Renderer\Inline\LinkInlineEntityRenderer
    calls:
        - [setClassName, ['u-link']]
    tags:
        - { name: draftjs.inline_entity_renderer, alias: draftjs_link_inline_entity_renderer }
```

In order to be fully support by our rendering engine, you must tag your service with draftjs.inline\_entity\_renderer and you must extend AbstractInlineEntityRenderer who implement the InlineEntityRendererInterface interface.

Illustration with the LinkInlineEntityRenderer class:

```
namespace Acme\Bundle\DemoBundle\Renderer\Inline;

use M6Web\Bundle\DraftjsBundle\Renderer\Inline\AbstractInlineEntityRenderer;
use M6Web\Bundle\DraftjsBundle\Renderer\Helper\InlineRendererHelperTrait;
use M6Web\Bundle\DraftjsBundle\Model\DraftEntity;

class LinkInlineEntityRenderer extends AbstractInlineEntityRenderer
{
    const TAG_NAME = 'a';

    use InlineRendererHelperTrait;

    /**
     * @param DraftEntity $entity
     *
     * @return string
     */
    public function openTag(DraftEntity $entity)
    {
        $data = $entity->getData();

        $attributes = [];

        if (isset($data['url'])) {
            $attributes['href'] = $data['url'];
        }

        if (isset($data['target']) && '_self' !== $data['target']) {
            $attributes['target'] = $data['target'];
        }

        if (isset($data['nofollow']) && true === $data['nofollow']) {
            $attributes['rel'] = 'nofollow';
        }

        if ($this->className) {
            $attributes['class'] = $this->className;
        }

        return $this->openNode(self::TAG_NAME, $attributes);
    }

    /**
     * @return string
     */
    public function closeTag()
    {
        return $this->closeNode(self::TAG_NAME);
    }

    /**
     * @param string $type
     *
     * @return bool
     */
    public function supports($type)
    {
        return 'link' === $type;
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'link';
    }
}
```

Notice the use of [InlineRendererHelperTrait](#inline-renderer-helper)

### Adding custom block entity renderer

[](#adding-custom-block-entity-renderer)

Entity block renderer are used for displaying entity information as a block.

First define your service:

```
acme_demo.acme_block_entity_renderer:
    class: Acme\Bundle\DemoBundle\Renderer\Entity\AcmeBlockEntityRenderer
    parent: m6_web_draft_js.abstract_block_entity_renderer
    calls:
        - [setClassName, ['block-entity-acme']]
    tags:
        - { name: draftjs.block_entity_renderer, alias: draftjs_acme_block_entity_renderer }
```

In order to be fully support by our rendering engine, you must tag your service with draftjs.block\_entity\_renderer and you must extend AbstractBlockEntityRenderer who implement the BlockEntityRendererInterface interface.

Illustration with the LinkInlineEntityRenderer class:

```
namespace Acme\Bundle\DemoBundle\Renderer\Entity;

use M6Web\Bundle\DraftjsBundle\Renderer\Entity\AbstractBlockEntityRenderer;
use M6Web\Bundle\DraftjsBundle\Model\DraftEntity;

class AcmeBlockEntityRenderer extends AbstractBlockEntityRenderer
{
    /**
     * @param DraftEntity $entity
     *
     * @return string
     */
    public function render(DraftEntity $entity)
    {
        // generate content from the entity data
        $content = 'content of your acme block';

        return $this->templating->render($this->getTemplate(), [
            'className' => $this->getClassName(),
            'content' => $content,
        ]);
    }

    /**
     * @param string $type
     *
     * @return bool
     */
    public function supports($type)
    {
        return 'acme' === $type;
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'acme';
    }
}
```

Helpers
-------

[](#helpers)

### Inline renderer helper

[](#inline-renderer-helper)

```
trait InlineRendererHelperTrait
{
    /**
     * @param $tagName
     * @param array $attributes
     *
     * @return string
     */
    protected function openNode($tagName, array $attributes = [])
    {
        $strAttributes = $this->buildAttributes($attributes);

        return sprintf('', $tagName, $strAttributes);
    }

    /**
     * @param $tagName
     *
     * @return string
     */
    protected function closeNode($tagName)
    {
        return sprintf('', $tagName);
    }

    /**
     * Convert an array of attributes in string like http_build_query
     *
     * @param array $attributes
     *
     * @return string
     */
    protected function buildAttributes(array $attributes = [])
    {
        $strAttributes = array_map(function ($key) use ($attributes) {
            return sprintf('%s="%s"', $key, $attributes[$key]);
        }, array_keys(array_filter($attributes)));

        if (!$strAttributes) {
            return '';
        }

        return sprintf(' %s', implode(' ', $strAttributes));
    }
}
```

### Block renderer helper

[](#block-renderer-helper)

```
trait BlockRendererHelperTrait
{
    /**
     * Get text alignment from content block data
     *
     * @param ContentBlock $contentBlock
     *
     * @return null
     */
    protected function getTextAlignment(ContentBlock $contentBlock)
    {
        $data = $contentBlock->getData();

        if (isset($data['textAlignment'])) {
            return $data['textAlignment'];
        }

        return null;
    }

    /**
     * Build string class names from block and text alignment class names
     *
     * @param ContentBlock $contentBlock
     *
     * @return string
     */
    protected function buildClassNames(ContentBlock $contentBlock)
    {
        $textAlignment = $this->getTextAlignment($contentBlock);

        $classNames = [
            $this->getBlockClassName(),
        ];

        if ($textAlignment) {
            $classNames[] = $this->getTextAlignmentClassName($textAlignment);
        }

        return implode(' ', $classNames);
    }
}
```

###  Health Score

29

—

LowBetter than 59% of packages

Maintenance17

Infrequent updates — may be unmaintained

Popularity22

Limited adoption so far

Community16

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 50% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~5 days

Total

2

Last Release

3373d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/2069361?v=4)[Patrick](/maintainers/Bedrock)[@Bedrock](https://github.com/Bedrock)

![](https://avatars.githubusercontent.com/u/5878620?v=4)[Fabien de Saint pern](/maintainers/fabdsp)[@fabdsp](https://github.com/fabdsp)

---

Top Contributors

[![yohannpoli](https://avatars.githubusercontent.com/u/903021?v=4)](https://github.com/yohannpoli "yohannpoli (2 commits)")[![Doss](https://avatars.githubusercontent.com/u/107692?v=4)](https://github.com/Doss "Doss (1 commits)")[![GromNaN](https://avatars.githubusercontent.com/u/400034?v=4)](https://github.com/GromNaN "GromNaN (1 commits)")

---

Tags

phpsymfonybundleDraft.js

### Embed Badge

![Health badge](/badges/m6web-draftjs-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/m6web-draftjs-bundle/health.svg)](https://phpackages.com/packages/m6web-draftjs-bundle)
```

###  Alternatives

[harmbandstra/swagger-ui-bundle

Exposes swagger UI inside your Symfony project through a route (eg. /docs)

42867.3k](/packages/harmbandstra-swagger-ui-bundle)[inspector-apm/inspector-symfony

Code Execution Monitoring for Symfony applications.

2830.1k2](/packages/inspector-apm-inspector-symfony)[fpt/stripe-bundle

Stripe bundle for Symfony 5.4 / 6 / 7

1521.2k](/packages/fpt-stripe-bundle)[kismia/centrifugo-bundle

A Centrifugo bundle for Symfony

1122.4k](/packages/kismia-centrifugo-bundle)[maxbeckers/amazon-alexa-bundle

Symfony Bundle for amazon alexa skills.

132.1k](/packages/maxbeckers-amazon-alexa-bundle)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
