You need to set a number above, in the field named Wrap lines to
where now you have No automatic wrapping
. It's not so intuitive, indeed.
In the following screenshot, you can see how different settings of maximum and minimum line length for word wrapping affects the label. It's alwasy the same label, the only difference is that I changed the wrap lines to
value for maximum line length and minimum line lenght.
If you choose 4 characters max., after "this" we have the first wrap as the word is exactely 4 characters long. On the next line, we have just "is" (2 char.), because including the next word including the space character "is my" results already in 5 characters, thus more as we defined as maximum.
However, below, with a setting of 4 characters min., the first line is the same, it it has exactely 4 characters, thus the minimal number required is reached an a wrap is introduced. The second line is different: a word wrapping after "is" (as with the max. setting) would result in a 2 character line, thus too short for the minimal setting of 4 we defined: thus in this case, we have 5 characters on the second line: "this is". And so on.
As you can see, QGIS does not wrap inside of words - thus even with a setting of max. 4 characters, you get longer lines: "consists" (8 char.) or "definitely" (10 characters) are not wrapped.

If you want to have a text box (rectangle) around your label, this can be easily done. Go to the background tab and activate a rectangular background, setting size, color and everything you like. Than the box will always adapt to your text size and length of the rows. By the way, in the following screenshot, I used the Wrap on character
function to get the text on two lines.

However, the expression editor gives you a lot of possibilities to adapt word wrap so that you can define for example that the text should wrap in such a way as to get at least three rows or not more than two rows. See the next screenshot, where I used the expression to_int (length ("text" ) / 2) to have a data driven value for minimum word wrap to force two lines, indifferent of how long the text is: to_int (length ("text" ) / 2)
