244

I'd like to truncate a dynamically loaded string using straight JavaScript. It's a url, so there are no spaces, and I obviously don't care about word boundaries, just characters.

Here's what I got:

var pathname = document.referrer; //wont work if accessing file:// paths
document.getElementById("foo").innerHTML = "<a href='" + pathname +"'>" + pathname +"</a>"
Brett DeWoody
  • 59,771
  • 29
  • 135
  • 184
Bob
  • 2,738
  • 3
  • 18
  • 12
  • 2
    What part do you want to truncate? Your example doesn't convey the intent very well. – Larsenal Aug 19 '09 at 17:44
  • 1
    oh ok- I want to truncate the URL at a certain amount of characters, so that when I set the innerHTML of "foo" it won't flow out of the div if it is too long. – Bob Aug 19 '09 at 17:45
  • 1
    *but- just the innerHTML, not the var pathname itself. – Bob Aug 19 '09 at 17:46
  • 1
    Why not just use css to hide the overflow of the div? overflow: hidden – Samuel Aug 19 '09 at 18:42
  • 3
    @Samuel Because it would be poor practice UI-wise- if the user is expecting to see the url they just came from (document.referrer), and I am shortening it, I want to indicate to them that they are only seeing a portion of the url, and that there was not an error. Aside from that, the method you propose would cut characters in half which would look horrible. – Bob Aug 19 '09 at 22:02
  • 1
    you should use css – zamzam Sep 29 '16 at 17:19

16 Answers16

437

Use the substring method:

var length = 3;
var myString = "ABCDEFG";
var myTruncatedString = myString.substring(0,length);
// The value of myTruncatedString is "ABC"

So in your case:

var length = 3;  // set to the number of characters you want to keep
var pathname = document.referrer;
var trimmedPathname = pathname.substring(0, Math.min(length,pathname.length));

document.getElementById("foo").innerHTML =
     "<a href='" + pathname +"'>" + trimmedPathname + "</a>"
Larsenal
  • 49,878
  • 43
  • 152
  • 220
  • 2
    If you want a substring starting from 0, then the substr function will do the exact same thing with 3 less chars ;) – jackocnr Sep 21 '14 at 18:55
  • 3
    substr behave weird if the string is shorter than the `length` - returns empty – RozzA Mar 26 '15 at 22:20
  • 1
    If your "string" is a number you also need to insert `.toString().` to convert it to a string that `substring()` can handle. – not2qubit Jan 26 '18 at 12:12
  • 1
    [MDN docs are better than W3schools](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring) – BigRon Sep 10 '19 at 13:19
46

Here's one method you can use. This is the answer for one of FreeCodeCamp Challenges:

function truncateString(str, num) {
  if (str.length > num) {
    return str.slice(0, num) + "...";
  } else {
    return str;
  }
}
Josh Harrison
  • 5,927
  • 1
  • 30
  • 44
mandrei100
  • 581
  • 4
  • 4
  • 1
    This can return a string that is longer than num due to the "...". And if the string is shorter than three you also don't want to append the "..." Here's a better way, sorry not sure how to format it in a comment: function truncate(input, length) { if (input.length <= length) return input; if (length < 3) return input.substring(0, length); return input.substring(0, length - 3) + '...'; } – Andy Mar 03 '23 at 22:05
19

Updated ES6 version

const truncateString = (string = '', maxLength = 50) => 
  string.length > maxLength 
    ? `${string.substring(0, maxLength)}…`
    : string

// demo the above function
alert(truncateString('Hello World', 4));
Sam Logan
  • 3,343
  • 2
  • 17
  • 13
  • this always invokes substring, even when it might not be necessary... – Clint Eastwood Jan 10 '20 at 14:48
  • @ClintEastwood good feedback, I have updated the answer. Checking the string length vs the max length also meant I could remove the showDots const and ternary making it tidier. Cheers. – Sam Logan Jan 12 '20 at 07:09
18

yes, substring. You don't need to do a Math.min; substring with a longer index than the length of the string ends at the original length.

But!

document.getElementById("foo").innerHTML = "<a href='" + pathname +"'>" + pathname +"</a>"

This is a mistake. What if document.referrer had an apostrophe in? Or various other characters that have special meaning in HTML. In the worst case, attacker code in the referrer could inject JavaScript into your page, which is a XSS security hole.

Whilst it's possible to escape the characters in pathname manually to stop this happening, it's a bit of a pain. You're better off using DOM methods than fiddling with innerHTML strings.

if (document.referrer) {
    var trimmed= document.referrer.substring(0, 64);
    var link= document.createElement('a');
    link.href= document.referrer;
    link.appendChild(document.createTextNode(trimmed));
    document.getElementById('foo').appendChild(link);
}
bobince
  • 528,062
  • 107
  • 651
  • 834
  • i'm confused, how does your solution avoid the security hole? – Bob Aug 19 '09 at 21:57
  • 11
    When you use DOM methods like ‘createTextNode’ and ‘.href=...’, you are directly setting the real underlying plaintext value. When you are writing HTML, either in an HTML file or through innerHTML, you must obey HTML escaping rules. So whilst ‘createTextNode('A – bobince Aug 19 '09 at 23:46
14

Following code truncates a string and will not split words up, and instead discard the word where the truncation occurred. Totally based on Sugar.js source.

function truncateOnWord(str, limit) {
        var trimmable = '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u2028\u2029\u3000\uFEFF';
        var reg = new RegExp('(?=[' + trimmable + '])');
        var words = str.split(reg);
        var count = 0;
        return words.filter(function(word) {
            count += word.length;
            return count <= limit;
        }).join('');
    }
Beto Frega
  • 956
  • 6
  • 21
10

Thought I would give Sugar.js a mention. It has a truncate method that is pretty smart.

From the documentation:

Truncates a string. Unless split is true, truncate will not split words up, and instead discard the word where the truncation occurred.

Example:

'just sittin on the dock of the bay'.truncate(20)

Output:

just sitting on...
Brian
  • 37,399
  • 24
  • 94
  • 109
4

Yes, substring works great:

stringTruncate('Hello world', 5); //output "Hello..."
stringTruncate('Hello world', 20);//output "Hello world"

var stringTruncate = function(str, length){
  var dots = str.length > length ? '...' : '';
  return str.substring(0, length)+dots;
};
4

One line ES6 Solution

Instead of just truncating the string, it also adds an ending string if the string length exceeds the given length.

const limit = (string, length, end = "...") => {
    return string.length < length ? string : string.substring(0, length) + end
}

limit('Hello world', 5) // Hello...
Bedram Tamang
  • 3,748
  • 31
  • 27
2
var str = "Anything you type in.";
str.substring(0, 5) + "" //you can type any amount of length you want
2

Besides the substring method, i found a nice little JS lib for this purpose.

It has mutliple useful methods in vanilla javascript to truncate a string.

Truncation by characters:

var pathname = 'this/is/thepathname';
document.getElementById("foo").innerHTML = "<a class='link' href='" + pathname +"'>" + pathname +"</a>"

// call the plugin - character truncation only needs a one line init
new Cuttr('.link', { length: 10 });
<script src="https://cdnjs.cloudflare.com/ajax/libs/cuttr/1.3.2/cuttr.min.js"></script>

<div id="foo"></div>

Simply add a class to the a and init the plugin.

Multiline text clipping is also possible.
More options like word oder sentences truncation are mentioned in the cuttr.js docs on the github page.

Basbee
  • 59
  • 2
2

For truncating a String to a specific length, use the following one-linear arrow function in JavaScript:

const truncate = (str, len) => str.slice?.(0, len);
    
console.log(truncate("Hello, World!", 5));
// Expected Output: Hello

The above function uses the String.prototype.slice method, which takes a chunk of a string and returns it as a new string without changing the original.

1

in case you want to truncate by word.

function limit(str, limit, end) {

      limit = (limit)? limit : 100;
      end = (end)? end : '...';
      str = str.split(' ');
      
      if (str.length > limit) {
        var cutTolimit = str.slice(0, limit);
        return cutTolimit.join(' ') + ' ' + end;
      }

      return str.join(' ');
    }

    var limit = limit('ILorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus metus magna, maximus a dictum et, hendrerit ac ligula. Vestibulum massa sapien, venenatis et massa vel, commodo elementum turpis. Nullam cursus, enim in semper luctus, odio turpis dictum lectus', 20);

    console.log(limit);
1

You can fix this method with the help of internal JavaScript methods

const truncate = (text, len) => {
  if (text.length > len && text.length > 0) {
    return `${text.split(" ").slice(0, len).join(" ")} ...`;
  } else {
    return text;
  }
};
mahdi
  • 21
  • 2
0

var pa = document.getElementsByTagName('p')[0].innerHTML;
var rpa = document.getElementsByTagName('p')[0];
// console.log(pa.slice(0, 30));
var newPa = pa.slice(0, 29).concat('...');
rpa.textContent = newPa;
console.log(newPa)
<p>
some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here some text here
</p>
sadeq alshaar
  • 673
  • 5
  • 8
0

In case you want to truncate by Limit (symbols), but you don't want to cut the words (leave the last word intact) for not LONG text (head of post for example):

trancWord(str, limit) {
    str = str.split(' ');
    let summ = 0
    for (let [index, value]  of str.entries()) {
        summ  += value.length
        if (summ > limit) {
            let cutTolimit = str.slice(0, index);
            return str.slice(0, index).join(' ') + ' ' + '...';
        }
    }
    return str.join(' ');
}

For long String (some long Text of Post - Vue-3 use as Filter):

trancWord  (str, max){
        if (str.length <= max) { return str; }
        let subString = str.substr(0, max);
        return (str ? subString.substr(0, subString.lastIndexOf(' ')) : subString) + '...';
}
Михаил
  • 74
  • 2
  • 5
0

The logic will be as follows

  • get the length of the string

  • if it is more than a threshold, get the substring and end with ellipsis or other notation

  • else, return the input string

    function truncateString(str: string, num: number, ending: string = '...') {
    return str.length > num ? str.slice(0, num) + ending : str; }

Saravanan
  • 7,637
  • 5
  • 41
  • 72
Zack
  • 21
  • 5
  • 2
    Please don't post code-only answers. The main audience, future readers, will be grateful to see explained *why* this answers the question instead of having to infer it from the code. Also, since this is an old question, please explain how it complements *all* other answers. – Gert Arnold Sep 17 '22 at 16:54