Initializing paragraph with styles

I am trying to solve the issues of setting the editor so that all text have a font-family style (no plain text)

I am trying to tell PM that all paragraphs need a font-family style. I tried keeping the current font in use in the schema spec and set the schema like this:

paragraph: {
	content: "inline<_>*",
	group: "block",
	toDOM(node) {
		return ["p", {style: 'font-family: \"'+node.type.schema.spec.fontFamily+'\"'}, 0] }

then whenever the user changes font in the menu I set schema.spec.fontFamily to the new font. I also initialize the schema.spec.fontFamily in the font dropdown constructor so that the first created paragraph has a correct font-family

(I also have a fontFamily mark for changing fonts inside paragraphs)

my question - is this a good approach to achieve what I want (no plain text & all text having font-family) or am I in the wrong direction ?

I was considering a plugin as an alternative that will check if a transaction is text and does not have a fontFamily mark and if so add one, but not sure how to implement that or if it’s better ?

Also I am not sure how to implement the paragraph’s parseDOM in the case above ?

Thank you!

If the font is global to your document, please use CSS the way it’s intended (i.e. simply set the font-family on the outer DOM element with the attributes prop)

thx marijn

this does not work properly :frowning:

If the user for example changes font to Arial, then type (in Arial) then insert for example a horizontal rule, and then keep typing text after the hrule - then font is back to default and is not Arial.

There can probably be any number of cases where prosemirror decides to insert a new paragraph and the font-family marks from before are gone, I need to make sure that any new text typed is in the currently selected font, not the default one in the CSS.

How can that be achieved ?

So your document can have multiple fonts like a normal word processor? Is this not the same as keeping marks? Make font a mark and make sure you always keep marks (same as bold/italics).

yes exactly, and I have made font a mark

how ? bold/italics do not keep mark if for example you add a horizontal rule (and I’m not sure they should …). As far as I can tell it is nowhere guaranteed that marks will persist across all added content.

Hmmm, there was a recent discussion around this where splitBlockKeepMarks was introduced as a solution. Perhaps this is not robust enough? I still use the path I mentioned:

Using the appendTransaction mechanism you can create a plugin that will grab the old marks and then ‘setStoredMarks’ on the current transaction.

So essentially, after all transactions that impact the doc, I reset the active marks.

Maybe a plugin like that would work for you?

well there can be a few approaches which is why I need marijn feedback

A plugin can work but tricky, I need to check that the transaction is text and that it doesn’t have those marks already (perhaps I can only check if it’s text and empty)

Then there is my solution above, storing the current font in the schema spec and changing the paragraph schema to have the marks on new paragraphs

Or we can have a toDOM for text (or is that already possible) ?

Or some other/better/new way

Storing it in the schema seems wrong. I think this is more what state is for. Perhaps you should store this in the editorState and then have your paragraph node depend on that? What happens if you want multiple fonts within a single paragraph? This would require it being a mark I think. Feels like a mark. I think you should go the mark route and figure out how to keep marks. This will set you up so that your bold/italic settings behave the same as your font setting.

yeah this is all in addition to having a font-family mark which handles font changes inside a paragraph and work well.

My problem is only for newly created paragraphs where I need a way to add those marks

Ideally I don’t want to add the mark to the paragraph, just to any new text inside it

following a lead from came up with this plugin:

appendTransaction(trs, oldState, newState) {
	if (trs.length !== 1 || trs[0].steps.length !== 1 || !trs[0].steps[0].slice.content.firstChild || trs[0].steps[0].slice.content.firstChild.marks.length > 0) return;

	const { fontFamily, fontSize } = getCurrFont();
	const schema = trs[0].doc.type.schema;
	const familyMark = schema.marks.fontFamily.create({ fontFamily }), sizeMark=schema.marks.fontSize.create({ fontSize });

	let newTr =
	trs.forEach(tr => {
		tr.steps.forEach(step => {
			step.getMap().forEach((oldStart, oldEnd, newStart, newEnd) => {
				newState.doc.nodesBetween(newStart, newEnd, (parentNode, parentPos) => {
					parentNode.forEach((childNode, childOffset) => {
						if (childNode.isText) newTr = newTr.addMark(newStart, newEnd, familyMark).addMark(newStart, newEnd, sizeMark)

	return newTr;

The good news is that it works :slight_smile: but

  • I am not confident about the test in the beginning, how do I safely recognize that I am in a the transaction of a newly created paragraph with no marks ?

  • it’s terribly involved, is there no simpler way ?