Create Custom Node with string, not populating inner text

I’ve created a custom Node using PM and tip for handling inline icons on our text editor. I was able to get it working well for ion-icons and font awesome. I’m struggling with the Material design icons as they follow a slightly different formatting:

a common icon for the html would be: <i class=""></i>"

but material icons is as follows: <i class="material-icons">{{class name}}</i>

my command function is as follows:

commands({ type }) {
		return (attrs) => {
			if (attrs && && {
				attrs.iconType =;
				attrs.iconId =;

			return function (state, dispatch) {
				let { $from, $to } = state.selection
				if (!$from.parent.canReplaceWith($from, $to, type))
				if (dispatch)
					if (attrs.iconType == 'material') {
						let { tr, schema } = state;
						let body = schema.text(`${attrs.iconId}`);
						let data = type.create(attrs, body);
						// dispatch(tr.insertText(attrs.iconId));
						// state.setSelection($from, $from + attrs.iconId.length);
						// wrapIn(type.create(attrs));
						tr.replaceSelectionWith(type.create(attrs, data));
						return dispatch(tr);
					} else {
						return dispatch(

The result for material icons is inserted into the correct place but is not populated with the icon class name in as text between the <i> tags.

I don’t think you want the text in your document representation. The node can just be a regular leaf node, and render the text in its toDOM method.

this is my toDOM function

toDOM: node => {
			let data = {}
			data['dw-icon-type'] = node.attrs.iconType
			data['dw-icon-id'] = node.attrs.iconId
			if (node.attrs.iconType == 'fontAwesome') {
				data['class'] = node.attrs.iconId
				return ["i", data]
			} else if (node.attrs.iconType == 'ion') {
				data['name'] = node.attrs.iconId
				return ["ion-icon", data]
			} else {
				data['class'] = 'material-icons'
				return ["i", data]

is there a way to populate data in between the tags? I though you could only attach inside the opening tag?

@marijn Thanks for planting the seed in my head! I was looking into playing around with the “children” of the node in the toDOM and was able to get the text to render!

for others with this issue: my toDOM became: return [“i”, data, ${node.attrs.nameofvariable}] the string was inserted as a direct child of the icon node