Automatically Shrinking TextArea to Fit Contents?

I have an application where I am (only) displaying data on a form (so all components have been set to read-only). One of these fields is a multi-line string that I am displaying in a TextArea (I have overridden the FormFieldFactory#createField() function to make the appropriate fields a TextArea).

Is there a way to automatically set the number of rows based on the content? For example, I want the TextArea to have a maximum size of 40 rows. If the content has fewer than 40 rows of text, then automatically size it to fit the content. However, if there are more than 40 rows of data, then keep the TextArea size set to 40 rows so that it will automatically add the scroll bars.

Right now I am statically setting the size to 40 rows, but if the content only has one or two lines in it, then there is a lot of extra white space.

Perhaps the
ExpandingTextArea
is what you are looking for?

It’s tagged as “experimental”, but seems to work quite well.

You could set a fixed column-count for the TextArea and then simply compute the necessary row-count.

Thank you, I will take a look.

EDIT: After reading the thread for the component, it says that it doesn’t support setting a max size, so it doesn’t quite fit my needs.

The column count is fixed at 80, but I also have word wrap disabled (so horizontal scroll bars will be added as needed automatically). Should this go in the createField() override, or somewhere after it is created?

EDIT: I tried counting the lines in createField() but it seems to make my application hang when trying to open the form.
EDIT2: It was an error in my line counting algorithm leading to an infinite loop. I’ll fix it and try again.
EDIT3: I got it working after fixing the algorithm. Thanks!

Here is the (pseudo)code I’m doing in case anybody wants to do the same thing:

public Field createField(Item item, Object propertyId, Component uiContext) {
    String pid = (String) propertyId;
    Field field;

    if (the pid is the one I want) {
        field = new TextArea(pid);
        String value = (String) item.getItemProperty(propertyId).getValue();
        if (value != null) {
            int numLines = 1;
            int index = -1;
            do {
                index = value.indexOf('\n', index + 1);
                if (index != -1) {
                    numLines++;
                }
            } while (index != -1);
            if (numLines <= 40) {
                ((TextArea) field).setRows(numLines);
            } else {
                ((TextArea) field).setRows(40);
            }
        } else {
            ((TextArea) field).setRows(2);
        }
        ((TextArea) field).setWidth(80, UNITS_EM);
        ((TextArea) field).setWordwrap(false);
        ((TextArea) field).setNullRepresentation("");
    } else {
        field = new TextField(pid);
        ((TextField) field).setNullRepresentation("");
    }

    // Make all fields read-only
    field.setReadOnly(true);

    return field;
}