Javascript: calculating number of columns of a dynamically sized textarea
Asked Answered
B

2

8

I've got an HTML textarea whose width is set to 100% of the browser window, using CSS.

How can I calculate how many columns of text fit within the textarea?

Betaine answered 19/7, 2009 at 7:28 Comment(0)
C
4

. @jes5199 I am writing to you from the future. I am roughly 11 years ahead of you and I come with news. Perhaps the best news I have is directly related to your question: it is entirely possible to calculate the cols in a text area. The second piece of news, is that I can rapidly demonstrate how to count a <textarea />'s columns with some handy web prototyping tools. The final piece of news I can share, is that you should absolutely without a doubt invest in Facebook, because I am going to use one of their magic javascript tools to quickly demonstrate how you can solve this problem. We have no idea how it works. It will be a few years before you'll enjoy such magic, but let's take a look at what the future has in store.

I have created a small CodeSandbox application that will calculate the number of columns in a text area here: https://codesandbox.io/s/stack-textarea-width-dkwij

The application depends on this function that performs the calculation you are looking for:

/**
 * calTextAreaCols -- function
 * @param {string} divId The element id of the `<textarea />` that requires measuring.
 * @param {string} font The font that is used in the targeted `<textarea />`.
 * @return {number} The number of characters / columns that fit within the width of the `<textarea />`
 */
export default function calcTextAreaCols(divId, font) {
  // get div font size; from: https://stackoverflow.com/a/15195345
  var element = document.getElementById(divId);
  var style = window
    .getComputedStyle(element, null)
    .getPropertyValue("font-size");
  var fontSize = parseFloat(style) + "px";

  // prepare environment to figure out row maximum; from: https://stackoverflow.com/a/21015393
  var canvas =
    calcTextAreaCols.canvas ||
    (calcTextAreaCols.canvas = document.createElement("canvas"));
  var context = canvas.getContext("2d");
  context.font = fontSize + " " + font;

  // <textarea> offsetWidth, minus border and padding
  var rawWidth = element.offsetWidth;
  rawWidth -= parseInt(
    getComputedStyle(element, null).getPropertyValue("border-left-width")
  );
  rawWidth -= parseInt(
    getComputedStyle(element, null).getPropertyValue("border-right-width")
  );
  rawWidth -= parseInt(
    getComputedStyle(element, null).getPropertyValue("padding-left")
  );
  rawWidth -= parseInt(
    getComputedStyle(element, null).getPropertyValue("padding-right")
  );

  // <textarea> width, divided by the width of the 'a' character
  rawMeasure = rawWidth / context.measureText("a").width;

  // round down
  var measure = Math.floor(rawMeasure);

  return measure;
}

Essentially this function will use a <canvas> element to determine how many characters can fit within the width of your <textarea /> element.

In my demo above there are some apparent flaws that I will note, but I leave it in your trusty hands to go from here:

  1. This calculation works only if the font styled to the <textarea /> is uniform, like monospace. If the characters are different widths, then that needs to be accounted for with some additional code.
  2. In the simple React App I created, you will see that the setTextAreaCols hook is only called on re-render and when the user inputs new information into the <textarea /> but not necessarily when the element is resized.
Convergent answered 8/9, 2020 at 23:59 Comment(2)
this is a nice answer, but the demo gives me inaccurate results both in chrome and firefox [ubuntu 18.04]Seigel
thank you @marcosassis for identifying this bug, I tested on Firefox and Chrome [Debian 10.5] and you are right, the calculation was slightly off. I believe this was due to the padding and border of the <textarea /> and now that the function accounts for those pixels (it was only off by 4px, but it was enough on my end to throw off the calculation by 2 chars), it appears to be working well. Can you confirm on your end? The CodeSandbox is updated with this function too.Convergent
B
-3

The DOM textarea object supports a method cols that can be used to get or set the number of column of the textarea.

var numCols = document.getElementById('myTextArea').cols

More info on Textarea at w3cschools.

Burse answered 20/7, 2009 at 4:8 Comment(2)
not helpful - "cols" returns "-1" if the textarea is dynamically sizedBetaine
I think your best bet then is to use document.getElementById("myTextArea").clientWidth) and/or document.getElementById("myTextArea").offsetWidth) and divide by the various factors affecting your font width. Or check out extjs.com/deploy/dev/docs/?class=Ext.util.TextMetricsBurse

© 2022 - 2024 — McMap. All rights reserved.