# Downcast helpers – model to view conversion

This article lists all editor helpers available in the [downcast conversion](../downcast.md).

<a id="element-to-element-conversion-helper">

## Element to element conversion helper

Converting a model element to a view element is the most common case of conversion. It is used to create view elements like `<p>` or `<h1>`, that we call “container elements.”

When using the `elementToElement()` helper, a **single model element** will be converted to a **single view element**. The children of this model element need to have their own converters defined and the engine will recursively convert them and insert into the created view element.

<a id="basic-element-to-element-conversion">

### Basic element to element conversion

If you want to convert a model element to a simple view element without any additional attributes, simply provide their names through the converter, as shown in this example:

```js
editor.conversion
	.for( 'downcast' )
	.elementToElement( {
		model: 'paragraphSeparator',
		view: 'hr'
} );
```

<a id="using-view-element-definition">

### Using view element definition

Sometimes you may need to output a view element that has certain attributes, like a class name. To achieve this, you can provide an [element definition](../../../../api/module_engine_view_elementdefinition-ViewElementDefinition.md) in the `view` property:

```js
editor.conversion
	.for( 'downcast' )
	.elementToElement( {
		model: 'fancyParagraph',
		view: {
			name: 'p',
			classes: 'fancy'
		}
	} );
```

Check out the [`ViewElementObjectDefinition` documentation](../../../../api/module_engine_view_elementdefinition-ViewElementObjectDefinition.md) for more details.

<a id="creating-a-view-element-using-a-callback">

### Creating a view element using a callback

An alternative way to write a converter from the previous section using a callback would look as follows:

```js
editor.conversion
	.for( 'downcast' )
	.elementToElement( {
		model: 'fancyParagraph',
		view: ( modelElement, { writer } ) => {
			return writer.createContainerElement(
				'p', { class: 'fancy' }
			);
		}
	} );
```

Here, the second parameter of the view callback is the [DowncastConversionApi](../../../../api/module_engine_conversion_downcastdispatcher-DowncastConversionApi.md) object. It contains many properties and methods that can be useful when writing a more complex converters.

The callback should return a single container element. This element should not contain any children except UI elements. If you want to create a richer structure, use the `elementToStructure()` method.

<a id="handling-model-elements-with-attributes">

### Handling model elements with attributes

If the view element does not only depend on the model element itself but also on its attributes, you need to specify these attributes in the `model` property.

```js
editor.conversion
	.for( 'downcast' )
	.elementToElement( {
		model: {
			name: 'heading',
			attributes: [ 'level' ]
		},
		view: ( modelElement, { writer } ) => {
			return writer.createContainerElement(
				'h' + modelElement.getAttribute( 'level' )
			);
		}
	} );
```

> **Note**
>
> If you forget to specify these attributes, the converter will still work for the insertion of the model element part but it will not handle any changes of the attribute value.

<a id="changing-converter-priority">

### Changing converter priority

In case there are other converters with overlapping `model` patterns already present, you can prioritize your converter to override these. To do that, use the `converterPriority` property:

```js
editor.conversion
	.for( 'downcast' )
	.elementToElement( {
		model: 'userComment',
		view: 'div'
	} );

editor.conversion
	.for( 'downcast' )
	.elementToElement( {
		model: 'userComment',
		view: 'article',
		converterPriority: 'high'
	} );
```

In the example above, the first converter has no explicitly set priority hence it assumes default priority, which is `normal`. The second one overrides it by setting the priority to `high`. Using both of these converters at once will result in the `<userComment>` element being converted to an `<article>` element.

This solution may also be handy if you want your converter to act as a fallback when other converters for a given element are not present (for example, a plugin has not been loaded). It can be easily achieved by setting the `converterProperty` to `low`.

<a id="element-to-structure-conversion-helper">

## Element to structure conversion helper

Convert a single model element to multiple view elements (a structure of view elements).

<a id="handling-empty-model-elements">

### Handling empty model elements

To convert a single model element `horizontalLine` to the following structure:

```html
<div class="horizontal-line">
	<hr />
</div>
```

you can use a converter similar to this one:

```js
editor.conversion
	.for( 'downcast' )
	.elementToStructure( {
		model: 'horizontalLine',
		view: ( modelElement, { writer } ) => {
			return writer.createContainerElement( 'div', { class: 'horizontal-line' }, [
				writer.createEmptyElement( 'hr' )
			] );
		}
} );
```

Note that in this example we create two elements, which is not possible by using the previously mentioned `elementToElement()` helper.

> **Note**
>
> For editor users, the best way to interact with complex structures is to act as independent entities and stay intact, for instance, when copied, pasted, and edited. CKEditor 5 allows that through the [widget API](../../../../api/module_widget_utils.md#function-toWidget). If you want to learn how to use it on top of `elementToStructure()`, be sure to check out the [Implementing a block widget](../../../tutorials/widgets/implementing-a-block-widget.md) tutorial.

<a id="handling-model-elements-children">

### Handling model element’s children

The example above uses an empty model element. If your model element may contain children, you need to specify where in the view these children should be placed. To do that, use the `writer.createSlot()` helper.

```js
editor.conversion
	.for( 'downcast' )
	.elementToStructure( {
		model: 'wrappedParagraph',
		view: ( modelElement, conversionApi ) => {
			const { writer } = conversionApi;
			const paragraphViewElement = writer.createContainerElement( 'p', {}, [
				writer.createSlot()
			] );

			return writer.createContainerElement( 'div', { class: 'wrapper' }, [
				paragraphViewElement
			] );
		}
	} );
```

> **Note**
>
> For editor users, the best way to interact with complex structures is to act as independent entities and stay intact, for instance, when copied, pasted, and edited. CKEditor 5 allows that through the [widget API](../../../../api/module_widget_utils.md#function-toWidget). If you want to learn how to use it on top of `elementToStructure()`, be sure to check out the [Implementing a block widget](../../../tutorials/widgets/implementing-a-block-widget.md) tutorial.

<a id="attribute-to-element-conversion-helper">

## Attribute to element conversion helper

The attribute to element conversion is used to create formatting view elements like `<b>` or `<span style="font-family: ...">` (that we call attribute elements). In this case, we do not convert a model element but a text node’s attribute. It is important to note that text formatting, such as bold or font size, should be represented in the model as text node attributes.

> **Note**
>
> In general, the model does not implement a concept of “inline elements” (in the sense in which they are defined by CSS). The only scenarios in which inline elements can be used, are self-contained objects such as soft breaks (`<br>`) or inline images.

<a id="basic-text-attribute-to-model-conversion">

### Basic text attribute to model conversion

```js
editor.conversion
	.for( 'downcast' )
	.attributeToElement( {
		model: 'bold',
		view: 'strong'
	} );
```

A model text node `"CKEditor&nbsp;5"` with a `bold` attribute will become a `<strong>"CKEditor&nbsp;5"</strong>` in the view.

<a id="using-view-element-definition-2">

### Using view element definition

You might want to output a view element that has more attributes, like a class name. To achieve that, you can provide an [element definition](../../../../api/module_engine_view_elementdefinition-ViewElementDefinition.md) in the `view` property:

```js
editor.conversion
	.for( 'downcast' )
	.attributeToElement( {
		model: 'invert',
		view: {
			name: 'span',
			classes: [ 'font-light', 'bg-dark' ]
		}
	} );
```

Check out the [`ViewElementObjectDefinition` documentation](../../../../api/module_engine_view_elementdefinition-ViewElementObjectDefinition.md) for more details.

<a id="creating-a-view-element-using-a-callback-2">

### Creating a view element using a callback

You can also generate the view element by a callback. This method is useful when the view element depends on the value of the model attribute.

```js
editor.conversion
	.for( 'downcast' )
	.attributeToElement( {
		model: 'bold',
		view: ( modelAttributeValue, conversionApi ) => {
			const { writer } = conversionApi;

			return writer.createAttributeElement( 'span', {
				style: 'font-weight:' + modelAttributeValue
			} );
		}
	} );
```

The second parameter of the view callback is the [DowncastConversionApi](../../../../api/module_engine_conversion_downcastdispatcher-DowncastConversionApi.md) object. It contains many properties and methods that can be useful when writing more complex converters.

<a id="changing-converter-priority-2">

### Changing converter priority

In case there are other converters already present, you can prioritize your converter to override the existing ones. To do that, use the `converterPriority` property:

```js
editor.conversion
	.for( 'downcast' )
	.attributeToElement( {
		model: 'bold',
		view: 'strong'
	} );

editor.conversion
	.for( 'downcast' )
	.attributeToElement( {
		model: 'bold',
		view: 'b',
		converterPriority: 'high'
	} );
```

In the example above, the first converter has no explicitly set priority hence it assumes default priority, which is `normal`. The second one overrides it by setting the priority to `high`. Using both of these converters at once will result in the `bold` attribute being converted to a `<b>` element.

<a id="attribute-to-attribute-conversion-helper">

## Attribute to attribute conversion helper

The `attributeToAttribute()` helper allows registering a converter that handles a specific attribute and converts it to an attribute of a view element.

Usually, when registering converters for elements (for example, by using `elementToElement()` or `elementToStructure()`), you will want to handle their attributes while handling the element itself.

The `attributeToAttribute()` helper comes in handy when for some reason you cannot cover a specific attribute inside the `elementToElement()` helper. For instance, when you are extending someone else’s plugin.

> **Note**
>
> This type of converter helper only works if there is already an element converter provided. Trying to convert to an attribute while there is no receiving view element will cause an error.

<a id="basic-attribute-to-attribute-conversion">

### Basic attribute to attribute conversion

This conversion results in adding an attribute to a view node, basing on an attribute from a model node. For example, `<imageInline src='foo.jpg'></imageInline>` is converted to `<img src='foo.jpg'></img>`.

```js
editor.conversion
	.for( 'downcast' )
	.attributeToAttribute( {
		model: 'source',
		view: 'src'
	} );
```

<a id="converting-specific-model-element-and-attribute">

### Converting specific model element and attribute

The converter in the example above will convert **all** the `source` model attributes in the document. You can limit its scope by providing the model element name. You achieve it with the following code:

```js
editor.conversion
	.for( 'downcast' )
	.attributeToAttribute( {
		model: {
			name: 'imageInline',
			key: 'source'
		},
		view: 'src'
	} );
```

This updated converter will only convert the `source` model attributes present on the `imageInline` model element.

<a id="creating-a-custom-view-element-from-a-selected-list-of-model-values">

### Creating a custom view element from a selected list of model values

Once you provide the array in the `model.values` property, the `view` property is expected to be an object with keys matching these values. This is best explained using the example below:

```js
editor.conversion
	.for( 'downcast' )
	.attributeToAttribute( {
		model: {
			name: 'styled',
			values: [ 'dark', 'light' ]
		},
		view: {
			dark: {
				key: 'class',
				value: [ 'styled', 'styled-dark' ]
			},
			light: {
				key: 'class',
				value: [ 'styled', 'styled-light' ]
			}
		}
	} );
```

<a id="creating-a-view-attribute-with-a-custom-value-based-on-the-model-value">

### Creating a view attribute with a custom value based on the model value

The value of the view attribute can be modified in the converter. Below is a simple mapper that sets the class attribute based on the model attribute value:

```js
editor.conversion
	.for( 'downcast' )
	.attributeToAttribute( {
		model: 'styled',
		view: modelAttributeValue => ( {
			key: 'class',
			value: 'styled-' + modelAttributeValue
		} )
	} );
```

It is worth noting that providing a style property in this manner requires the returned `value` to be an object:

```js
editor.conversion
	.for( 'downcast' )
	.attributeToAttribute( {
		model: 'lineHeight',
		view: modelAttributeValue => ( {
			key: 'style',
			value: {
				'line-height': modelAttributeValue,
				'border-bottom': '1px dotted #ba2'
			}
		} )
	} );
```

<a id="changing-converter-priority-3">

### Changing converter priority

You can override the existing converters by specifying higher priority, like in the example below:

```js
editor.conversion
	.for( 'downcast' )
	.attributeToAttribute( {
		model: 'source',
		view: 'href'
	} );

editor.conversion
	.for( 'downcast' )
	.attributeToAttribute( {
		model: 'source',
		view: 'src',
		converterPriority: 'high'
	} );
```

First converter has the default priority, `normal`. The second converter will be called earlier because of its higher priority, thus the `source` model attribute will get converted to `src` view attribute instead of `href`.

<a id="further-reading">

## Further reading

Check out the [dedicated guide](upcast.md) with a full list of complementary [upcast conversion helpers](../upcast.md).

---

Full index of the CKEditor 5 documentation: [llms.txt](../../../../../llms.txt)
