I wrote the details in another comment. You can find references here:
https://dev.mysql.com/doc/refman/8.0/en/innodb-row-format.ht...
and here:
https://dev.mysql.com/doc/refman/8.0/en/storage-requirements...
"Bad performance" is not exact. I'd say "worse" performance, in the cases where TEXTs cause extra page accesses. The distinction is important because in some cases, a performance that is "negligibly worse" can still be "good" - as in general, in software engineering :-)
I still feel dirty using TEXT though.
In the days of spinny-disks this was a pretty huge penalty, you couldn't do linear reads to get the data, the heads would have to veer over to that other sector, read a bit of data, then skip back to read the next row. That was especially punishing as no amount of disk cache could help buffer against these reads that, to the operating system, seemed completely random.
MySQL moved the first X bytes of this data into the table row structure a while back (5.6? 5.7?) for performance reasons. It will only skip to the blob-data storage area if the data is longer than can fit in the size put in-row.
If you really cared you'd do your own homework.
In PostgreSQL, TEXT/VARCHAR (same type) is only stored outside the tuple if it's large.