Apply font styles to Selection

Hi, is there a way to apply font size and other font styles to the Selection only? We used to use transaction.setNodeMarkup, but it applies styles on the whole node and I need on the selection only.

For example, I have a paragraph like: “Here is some text”. Then, I highlight a word text and want to make it 18px (other words are 16px), but font size changes on the whole paragraph, and not only on this word.

Thanks

How font size is modeled depends on your schema—if it’s an attribute on nodes, then it can only be set per-node. If it’s a mark (which seems unlikely if you’re using setNodeMarkup right now), it can be added to specific ranges with addMark.

thanks for the answer ) what I trying to do is to modify somehow setNodeMarkup function. Here is what I got. But now I get the error: “Invalid content type for paragraph”. ReplaceAroundStep is set on the node only too?

const node = editorView.state.doc.nodeAt(pos);
  const { tr } = editorView.state;
  if (!node) throw new RangeError("No node at given position");

  const newNode = type.create(attrs, null, marks || node.marks);
  if (node.isLeaf) return tr.replaceWith(pos, pos + node.nodeSize, newNode);

  const slice = new Slice(Fragment.from(newNode), 0, 0);

  return tr.step(new ReplaceAroundStep(from, to, from - 1, to, slice, 1, true));

Without knowing what your schema looks like, and what kind of structure change you’re trying to create, I can’t really say what’s going on here.

Here is my schema for paragraph node:

export const paragraph = {
  group: "block",
  attrs: {
    fontFamily: {
      default: "fontArchivo",
    },
    fontSize: {
      default: null,
    },
    textAlign: {
      default: "left",
    },
  },
  content: "inline*",
  toDOM(node) {
    return [
      "p",
      {
        class: node.attrs.fontFamily,
        style: `${
          node.attrs?.fontSize && `font-size: ${node.attrs?.fontSize}px`
        }; ${node.attrs?.textAlign && `text-align: ${node.attrs?.textAlign}`};`,
      },
      0,
    ];
  },
  parseDOM: [
    {
      tag: "p",
    },
  ],
};

I want to change fontSize and fontFamily attrs not for the whole paragraph but only for the selected piece of paragraph. setNodeMarkup applies the changes to the whole paragraph, therefore, I’m trying to modify this function.

Look into using marks, rather than node attributes, to represent font size and family.

Thanks! I implemented font size and font family as marks. But now have the problem that on start marks is not detected. What I mean: for example, I have this paragraph node where every word has different font size:

fontSize14 fontSize16 fontSize18

If I select the first letter (in this example f), the mark will be not detected here. It happens because before f - not mark, and after f - mar exists. But if I select the last letter, then everything fine, the mark is detected before this letter and after it. The question is how can I detect the mark before the first letter? I added the inclusive option to marks, so it detects the mark after the last letter. Below, is my mark:

export const fontSize = {
  attrs: {
    fontSize: {
      default: null,
    },
  },
  inclusive: true,
  parseDOM: [
    {
      tag: "span",
      getAttrs: node => ({ fontSize: node.getAttribute("fontSize") }),
    },
  ],

  toDOM(node) {
    return [
      "span",
      {
        style: `${
          node.attrs?.fontSize && `font-size: ${getFontSize(node)}px`
        };`,
      },
      0,
    ];
  },
};

Also, it affects the case when I want to start a new line and I cannot select a different font size before typing something. It doesn’t happened with the strong mark, for example

Here is a gif to show what I mean. The cursor is set as for default value but after I starting typing it gets bigger.

Is there a way to avoid this cursor jumping?

1 Like

Right, with marks, the font size won’t be rendered unless there is any actual text that it’s applied to visible. That’s not something the library will solve for you.

Can I change the font style by using this library? Please give me the solution to this problem.

1 Like

@marijn heyy!! I’ve implemented same feature for setting dynamic font styles. i’m getting an issue in it like after changing the font-size and saved and again if we open that post then it always set to default font-size. how can i store the last used font-size? how can i achieve this?

If you store it in mark attributes, and then call state.toJSON(), state.fromJSON(), the mark attribtues will be serialized and deserialzied automatically. You want to make sure that font-size is being stored somewhere in your state being serialized.

Here’s a code sandbox showing how you can use marks to set font size styles. Hopefully this helps someone.

1 Like

heyy @moonrise-tk thanks for the suggestion. is there any other ways i can achieve this?? i got into situation that i can’t be use JSON here.

thanks again :slightly_smiling_face: