Str::limit

Truncates a string to a maximum display width and appends an ellipsis, optionally without splitting a word.

Signature
Str::limit(string $value, int $limit = 100, string $end = '...', bool $preserveWords = false): string

Parameters

ParameterTypeDescription
$$valuestringThe string to truncate.
$$limitoptionalint= 100Maximum display width to keep, measured with mb_strwidth. The width of $end is not counted against it.
$$endoptionalstring= '...'String appended after truncation. Pass an empty string to append nothing.
$$preserveWordsoptionalbool= falseWhen true, the cut is pulled back to the last whitespace so no word is split; the input is also run through strip_tags and has newlines collapsed to spaces first.

Return value

stringThe original string when it already fits, otherwise the truncated string with $end appended.

Changelog

  • PHP 11.xThe preserveWords argument was added. In 10.x and earlier, limit always cut at the exact width, mid-word.

Str::limit is the excerpt helper: shorten a description for a card, a subject line for a list, a log message for a column. If the value already fits, it is returned untouched and no ellipsis is added — so you never get Short....

It measures width, not characters

The check and the cut both use mb_strwidth / mb_strimwidth, which count East Asian wide characters as two columns. Ten Japanese characters have a width of 20, so Str::limit($japanese, 8) keeps four of them, not eight. For Latin text width and character count coincide, which is why this rarely surfaces until someone pastes CJK text.

The appended string is extra

$end is concatenated after truncation, so the result can be longer than $limit. Budget for it yourself if you are filling a fixed-width column: pass $limit - 3.

preserveWords changes more than the cut point

Setting it to true also strips HTML tags and collapses newlines before truncating — a quiet difference from the default branch, which leaves markup alone and can slice a tag in half. If you are truncating HTML for display, you want preserveWords: true, or you want to strip the tags yourself first.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Build a card excerpt from the first 120 characters of a post body.
  • Shorten a long error message before writing it to a fixed-width log column.
  • Trim a filename or subject line for a table cell without breaking a word.

Frequently asked questions

How do I truncate a string in Laravel without cutting a word in half?

Pass preserveWords: true, which pulls the cut back to the last whitespace before the limit. It was added in Laravel 11; on older versions you have to truncate and then trim back to the final space yourself.

Why is my truncated string longer than the limit I set?

Because $end is appended after truncation rather than counted against $limit, so a 20-character limit with the default '...' yields 23 characters. Pass $limit - strlen($end) when you need a hard maximum.

Why does Str::limit cut Japanese or Chinese text shorter than expected?

It measures display width with mb_strwidth, and CJK characters are two columns wide, so a limit of 8 keeps only four of them. Use mb_substr directly if you need an exact character count.

More examples

Truncating HTML, with and without preserveWords

The default branch treats the markup as ordinary text and cuts inside the <strong> tag, producing broken HTML. preserveWords runs strip_tags first, so it measures and truncates the visible text only. This is the usual reason an excerpt renders with a stray angle bracket.

Example · php
<?php

use Illuminate\Support\Str;

$html = '<p>The <strong>quick</strong> brown fox</p>';

echo Str::limit($html, 12), "\n";
// <p>The <stro...

echo Str::limit($html, 12, preserveWords: true), "\n";
// The quick...

Excerpts in a Blade view

Shows the three shapes you actually write in an application: a custom single-character ellipsis for headlines, word-preserving truncation for body copy, and the Stringable chain where squish collapses the whitespace left behind by stripped markup. Needs a booted application and Eloquent models.

Example · php
<?php

// resources/views/posts/index.blade.php
?>
@foreach ($posts as $post)
    <article>
        <h2>{{ Str::limit($post->title, 60, '…') }}</h2>

        <p>{{ Str::limit(strip_tags($post->body), 160, preserveWords: true) }}</p>

        {{-- The fluent form reads better in a chain --}}
        <small>{{ str($post->body)->stripTags()->squish()->limit(80) }}</small>
    </article>
@endforeach

Fitting a fixed-width column

Passing $width directly would have produced a 23-character cell and broken the table, because the '...' is added after the limit is applied rather than counted inside it.

Example · php
<?php

use Illuminate\Support\Str;

$width = 20;

$rows = [
    'orders.created',
    'notifications.channel.slack.dispatch.failed',
];

foreach ($rows as $row) {
    // Subtract the ellipsis, because $end is appended on top of $limit.
    $cell = Str::limit($row, $width - 3);

    echo '|', str_pad($cell, $width), "|\n";
}

// |orders.created      |
// |notifications.cha...|

Discussion

  • Be the first to comment on this lesson.