Skip to main content

Custom Block Rendering

This article discusses how to customize Draft default block rendering. The block rendering is used to define supported block types and their respective renderers, as well as converting pasted content to known Draft block types.

When pasting content, or when calling convertFromHTML, Draft will convert pasted content to the respective block rendering type by matching the Draft block render map with the matched tag.

Draft default block render map

HTML elementDraft block type
<h1/>header-one
<h2/>header-two
<h3/>header-three
<h4/>header-four
<h5/>header-five
<h6/>header-six
<blockquote/>blockquote
<pre/>code-block
<figure/>atomic
<li/>unordered-list-item,ordered-list-item**
<div/>unstyled***

** - Block type will be based on the parent <ul/> or <ol/>

*** - Any block that is not recognized by the block rendering mapping will be treated as unstyled

Configuring block render map

Draft's default block render map can be overwritten by passing an Immutable Map to the editor blockRender props.

example of overwriting default block render map:

// The example below deliberately only allows
// 'heading-two' as the only valid block type and
// updates the unstyled element to also become a h2.
const blockRenderMap = Immutable.Map({
'header-two': {
element: 'h2'
},
'unstyled': {
element: 'h2'
}
});

class RichEditor extends React.Component {
render() {
return (
<Editor
...
blockRenderMap={blockRenderMap}
/>
);
}
}

There are cases where instead of overwriting the defaults, we only want to add new block types. This can be done by using the DefaultDraftBlockRenderMap reference to create a new blockRenderMap

example of extending default block render map:

const blockRenderMap = Immutable.Map({
'section': {
element: 'section'
}
});

// Include 'paragraph' as a valid block and updated the unstyled element but
// keep support for other draft default block types
const extendedBlockRenderMap = Draft.DefaultDraftBlockRenderMap.merge(blockRenderMap);

class RichEditor extends React.Component {
render() {
return (
<Editor
...
blockRenderMap={extendedBlockRenderMap}
/>
);
}
}

When Draft parses pasted HTML, it maps from HTML elements back into Draft block types. If you want to specify other HTML elements that map to a particular block type, you can add the array aliasedElements to the block config.

example of unstyled block type alias usage:

'unstyled': {
element: 'div',
aliasedElements: ['p'],
}

Custom block wrappers

By default, the html element is used to wrap block types. However, a react component can also be provided to the blockRenderMap to wrap the EditorBlock.

During pasting, or when calling convertFromHTML, the html will be scanned for matching tag elements. A wrapper will be used when there is a definition for it on the blockRenderMap to wrap that particular block type. For example:

Draft uses wrappers to wrap <li/> inside either <ol/> or <ul/>, but wrappers can also be used to wrap any other custom block type.

example of extending default block render map to use a react component for a custom block:

class MyCustomBlock extends React.Component {
constructor(props) {
super(props);
}

render() {
return (
<div className='MyCustomBlock'>
{/* here, this.props.children contains a <section> container, as that was the matching element */}
{this.props.children}
</div>
);
}
}

const blockRenderMap = Immutable.Map({
'MyCustomBlock': {
// element is used during paste or html conversion to auto match your component;
// it is also retained as part of this.props.children and not stripped out
element: 'section',
wrapper: <MyCustomBlock />,
}
});

// keep support for other draft default block types and add our myCustomBlock type
const extendedBlockRenderMap = Draft.DefaultDraftBlockRenderMap.merge(blockRenderMap);

class RichEditor extends React.Component {
...
render() {
return (
<Editor
...
blockRenderMap={extendedBlockRenderMap}
/>
);
}
}